Completed API and redirect login test
feat: Update OAuth client handling and permissions, enhance authentication claims, and adjust environment settings
This commit is contained in:
parent
f9a66dccad
commit
09589ef631
@ -1,6 +1,8 @@
|
||||
ASPNETCORE_ENVIRONMENT=Development
|
||||
ConnectionStrings__Default=Host=localhost;Database=member_center;Username=postgres;Password=postgres
|
||||
Auth__Issuer=http://localhost:7850/
|
||||
Auth__WebLoginUrl=http://localhost:5080/account/login
|
||||
Auth__AllowedLoginReturnUrlPrefixes=http://localhost:7850/
|
||||
Auth__MemberCenterAudience=member_center_api
|
||||
Auth__SendEngineAudience=send_engine_api
|
||||
SendEngine__BaseUrl=http://localhost:6060
|
||||
|
||||
@ -162,6 +162,11 @@ public class AdminOAuthClientsController : ControllerBase
|
||||
|
||||
descriptor.DisplayName = request.Name;
|
||||
descriptor.ClientType = request.ClientType;
|
||||
if (string.Equals(request.ClientType, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
descriptor.ClientSecret = null;
|
||||
}
|
||||
|
||||
await ApplyPermissionsAsync(descriptor, request.Usage);
|
||||
descriptor.RedirectUris.Clear();
|
||||
foreach (var uri in redirectUris)
|
||||
|
||||
@ -56,6 +56,7 @@ public class OAuthController : ControllerBase
|
||||
}
|
||||
|
||||
var principal = await _signInManager.CreateUserPrincipalAsync(user);
|
||||
principal.SetClaim(OpenIddictConstants.Claims.Subject, user.Id.ToString());
|
||||
if (!string.IsNullOrWhiteSpace(user.SecurityStamp))
|
||||
{
|
||||
principal.SetClaim(SecurityStampClaimType, user.SecurityStamp);
|
||||
|
||||
@ -58,6 +58,7 @@ public class TokenController : ControllerBase
|
||||
}
|
||||
|
||||
var principal = await _signInManager.CreateUserPrincipalAsync(user);
|
||||
principal.SetClaim(OpenIddictConstants.Claims.Subject, user.Id.ToString());
|
||||
if (!string.IsNullOrWhiteSpace(user.SecurityStamp))
|
||||
{
|
||||
principal.SetClaim(SecurityStampClaimType, user.SecurityStamp);
|
||||
|
||||
@ -231,6 +231,12 @@ app.Use(async (context, next) =>
|
||||
{
|
||||
if (context.User.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
if (context.User.HasClaim(claim => claim.Type == "client_usage"))
|
||||
{
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
|
||||
var subject = context.User.FindFirstValue(OpenIddictConstants.Claims.Subject)
|
||||
?? context.User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:5050",
|
||||
"applicationUrl": "http://localhost:7850",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
|
||||
@ -79,7 +79,12 @@ public sealed class AuthResourceRegistryService : IAuthResourceRegistryService
|
||||
OpenIddictConstants.Scopes.OpenId,
|
||||
OpenIddictConstants.Scopes.Email,
|
||||
OpenIddictConstants.Scopes.Profile,
|
||||
"profile:basic.read"
|
||||
"profile:basic.read",
|
||||
"profile:basic.write",
|
||||
"profile:addresses.read",
|
||||
"profile:addresses.write",
|
||||
"profile:subscriptions.read",
|
||||
"profile:subscriptions.write"
|
||||
], cancellationToken);
|
||||
|
||||
await EnsureUsagePermissionsAsync("webhook_outbound", [
|
||||
|
||||
@ -11,6 +11,7 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Npgsql;
|
||||
using OpenIddict.Abstractions;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.CommandLine;
|
||||
@ -283,10 +284,60 @@ migrateCommand.SetHandler(async (string? connectionString, string? appsettings,
|
||||
Console.WriteLine("Migrations completed.");
|
||||
}, connectionStringOption, appsettingsOption, targetMigrationOption);
|
||||
|
||||
var syncOAuthClientsCommand = new Command("sync-oauth-clients", "Refresh OAuth client permissions from usage defaults");
|
||||
syncOAuthClientsCommand.AddOption(connectionStringOption);
|
||||
syncOAuthClientsCommand.AddOption(appsettingsOption);
|
||||
syncOAuthClientsCommand.SetHandler(async (string? connectionString, string? appsettings) =>
|
||||
{
|
||||
var resolvedConnection = ResolveConnectionString(connectionString, appsettings, noPrompt: true);
|
||||
if (string.IsNullOrWhiteSpace(resolvedConnection))
|
||||
{
|
||||
Console.Error.WriteLine("Connection string is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
var services = BuildServices(resolvedConnection);
|
||||
await using var scope = services.CreateAsyncScope();
|
||||
var registry = scope.ServiceProvider.GetRequiredService<IAuthResourceRegistryService>();
|
||||
await registry.EnsureDefaultsAsync();
|
||||
|
||||
var applicationManager = scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();
|
||||
var applications = new List<object>();
|
||||
await foreach (var application in applicationManager.ListAsync())
|
||||
{
|
||||
applications.Add(application);
|
||||
}
|
||||
|
||||
var updated = 0;
|
||||
foreach (var application in applications)
|
||||
{
|
||||
var properties = await applicationManager.GetPropertiesAsync(application);
|
||||
if (!properties.TryGetValue("usage", out var usageElement))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var usage = usageElement.GetString();
|
||||
if (string.IsNullOrWhiteSpace(usage))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var descriptor = new OpenIddictApplicationDescriptor();
|
||||
await applicationManager.PopulateAsync(descriptor, application);
|
||||
await ApplyOAuthClientPermissionsAsync(descriptor, registry, usage);
|
||||
await applicationManager.UpdateAsync(application, descriptor);
|
||||
updated++;
|
||||
}
|
||||
|
||||
Console.WriteLine($"OAuth clients synchronized: {updated}.");
|
||||
}, connectionStringOption, appsettingsOption);
|
||||
|
||||
root.AddCommand(initCommand);
|
||||
root.AddCommand(addAdminCommand);
|
||||
root.AddCommand(resetCommand);
|
||||
root.AddCommand(migrateCommand);
|
||||
root.AddCommand(syncOAuthClientsCommand);
|
||||
|
||||
return await root.InvokeAsync(args);
|
||||
|
||||
@ -303,6 +354,13 @@ static IServiceProvider BuildServices(string connectionString)
|
||||
options.UseOpenIddict();
|
||||
});
|
||||
|
||||
services.AddOpenIddict()
|
||||
.AddCore(options =>
|
||||
{
|
||||
options.UseEntityFrameworkCore()
|
||||
.UseDbContext<MemberCenterDbContext>();
|
||||
});
|
||||
|
||||
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
|
||||
{
|
||||
options.User.RequireUniqueEmail = true;
|
||||
@ -320,6 +378,37 @@ static IServiceProvider BuildServices(string connectionString)
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
static async Task ApplyOAuthClientPermissionsAsync(
|
||||
OpenIddictApplicationDescriptor descriptor,
|
||||
IAuthResourceRegistryService registry,
|
||||
string usage)
|
||||
{
|
||||
descriptor.Permissions.Clear();
|
||||
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Token);
|
||||
|
||||
if (UsesAuthorizationCodeFlow(usage))
|
||||
{
|
||||
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Authorization);
|
||||
descriptor.Permissions.Add(OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode);
|
||||
descriptor.Permissions.Add(OpenIddictConstants.Permissions.GrantTypes.RefreshToken);
|
||||
descriptor.Permissions.Add(OpenIddictConstants.Permissions.ResponseTypes.Code);
|
||||
}
|
||||
else
|
||||
{
|
||||
descriptor.Permissions.Add(OpenIddictConstants.Permissions.GrantTypes.ClientCredentials);
|
||||
}
|
||||
|
||||
var scopes = await registry.GetAllowedScopesForUsageAsync(usage);
|
||||
foreach (var scope in scopes)
|
||||
{
|
||||
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Prefixes.Scope + scope);
|
||||
}
|
||||
}
|
||||
|
||||
static bool UsesAuthorizationCodeFlow(string usage) =>
|
||||
string.Equals(usage, "web_login", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(usage, "webhook_outbound", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
static string? ResolveConnectionString(string? connectionString, string? appsettingsPath, bool noPrompt)
|
||||
{
|
||||
var targetPath = ResolveAppsettingsPath(appsettingsPath);
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
{
|
||||
"MemberCenter": {
|
||||
"ApiBaseUrl": "http://localhost:7850",
|
||||
"WebLoginClientId": "",
|
||||
"WebLoginClientId": "f48329ef38c54a62b627585a75c9b5d5",
|
||||
"WebLoginRedirectPath": "/auth/callback",
|
||||
"WebLoginScopes": "openid email profile profile:basic.read profile:basic.write profile:addresses.read profile:addresses.write profile:subscriptions.read profile:subscriptions.write",
|
||||
"ServiceClientId": "",
|
||||
"ServiceClientSecret": "",
|
||||
"ServiceClientId": "e9fe7ae413c54ae49432eca6474648d3",
|
||||
"ServiceClientSecret": "To/WaVObQgxCaZwzGexfp/pvUwI2G5o1r55v4sRukYw=",
|
||||
"ServiceScopes": "profile:basic.read profile:addresses.read"
|
||||
},
|
||||
"Logging": {
|
||||
|
||||
@ -204,6 +204,11 @@ public class OAuthClientsController : Controller
|
||||
|
||||
descriptor.DisplayName = model.Name;
|
||||
descriptor.ClientType = model.ClientType;
|
||||
if (string.Equals(model.ClientType, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
descriptor.ClientSecret = null;
|
||||
}
|
||||
|
||||
await ApplyPermissionsAsync(descriptor, model.Usage);
|
||||
descriptor.RedirectUris.Clear();
|
||||
foreach (var uri in redirectUris)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user