From 0f53ca81b85edb8c31911ee5e3a8afb35bebb7bb Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 11 Apr 2022 16:34:12 +0800 Subject: [PATCH] Refactor --- docs/en/Modules/OpenIddict.md | 17 ------ .../Account/OpenIddictSupportedLoginModel.cs | 18 +++--- .../OpenIddict.Demo.Client.Console.csproj | 2 + .../OpenIddict.Demo.Client.Console/Program.cs | 19 ++++++ .../OpenIddict.Demo.Server.csproj | 3 + .../OpenIddictServerModule.cs | 25 +++++++- .../app/OpenIddict.Demo.Server/Program.cs | 29 +++++---- .../AbpOpenIddictAspNetCoreModule.cs | 6 -- .../AbpOpenIddictTenantResolveContributor.cs | 36 ----------- ...aultOpenIddictClaimDestinationsProvider.cs | 18 +++--- .../TokenController.AuthorizationCode.cs | 61 ++++++++++--------- .../Controllers/TokenController.DeviceCode.cs | 61 ++++++++++--------- .../TokenController.RefreshToken.cs | 61 ++++++++++--------- .../Volo.Abp.OpenIddict.Domain.csproj | 2 +- .../AbpOpenIddictWildcardDomainBase.cs | 16 +++-- .../AbpOpenIddictWildcardDomainOptions.cs | 12 +++- 16 files changed, 200 insertions(+), 186 deletions(-) delete mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictTenantResolveContributor.cs diff --git a/docs/en/Modules/OpenIddict.md b/docs/en/Modules/OpenIddict.md index d7386afe5f..6df46dfcd2 100644 --- a/docs/en/Modules/OpenIddict.md +++ b/docs/en/Modules/OpenIddict.md @@ -105,23 +105,6 @@ UserInfoController -> connect/userinfo > We will implement the related functions of **device flow** in the PRO module.. -#### Identity authentication scheme - -The default ABP OpenIddict project includes several authentication schemes. - -* `Bearer`: Authenticate tokens issued by yourself(angular) -* `OpenIddict.Server.AspNetCore`: OpenIddict uses -* `Identity.Application`: Identity default authenticate scheme -* `Identity.External`: Identity external login uses -* `Identity.TwoFactorRememberMe`: Identity TwoFactor login uses -* `Identity.TwoFactorUserId`: Identity TwoFactor login uses - -This can break the multi-tenancy feature, Some OAuth requests may be authenticated by OpenIddict but not by `Identity.Application`. - -We have added a top priority `AbpOpenIddictTenantResolveContributor` service. It will try to get tenant info from OpenIddict authentication scheme. - -Please note the difference and usage scenarios between `Identity.Application` and `OpenIddict.Server.AspNetCore`. - #### How to control claims in access_token and id_token You can use the [Claims Principal Factory](https://docs.abp.io/en/abp/latest/Authorization#claims-principal-factory) to add/remove claims to the `ClaimsPrincipal`. diff --git a/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/Account/OpenIddictSupportedLoginModel.cs b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/Account/OpenIddictSupportedLoginModel.cs index c6f9ddad71..7e3ff1817a 100644 --- a/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/Account/OpenIddictSupportedLoginModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/Account/OpenIddictSupportedLoginModel.cs @@ -55,20 +55,20 @@ public class OpenIddictSupportedLoginModel : LoginModel if (action == "Cancel") { var request = await GetOpenIddictRequestFromReturnUrlAsync(ReturnUrl); - if (request?.ClientId == null) - { - return Redirect("~/"); - } var transaction = HttpContext.Features.Get()?.Transaction; + if (request?.ClientId != null && transaction != null) + { + transaction.EndpointType = OpenIddictServerEndpointType.Authorization; + transaction.Request = request; - transaction.EndpointType = OpenIddictServerEndpointType.Authorization; - transaction.Request = request; + var notification = new OpenIddictServerEvents.ValidateAuthorizationRequestContext(transaction); + transaction.SetProperty(typeof(OpenIddictServerEvents.ValidateAuthorizationRequestContext).FullName!, notification); - var notification = new OpenIddictServerEvents.ValidateAuthorizationRequestContext(transaction); - transaction.SetProperty(typeof(OpenIddictServerEvents.ValidateAuthorizationRequestContext).FullName!, notification); + return Forbid(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + } - return Forbid(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + return Redirect("~/"); } return await base.OnPostAsync(action); diff --git a/modules/openiddict/app/OpenIddict.Demo.Client.Console/OpenIddict.Demo.Client.Console.csproj b/modules/openiddict/app/OpenIddict.Demo.Client.Console/OpenIddict.Demo.Client.Console.csproj index c67abd2eed..8302a5d26e 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Client.Console/OpenIddict.Demo.Client.Console.csproj +++ b/modules/openiddict/app/OpenIddict.Demo.Client.Console/OpenIddict.Demo.Client.Console.csproj @@ -9,5 +9,7 @@ + + diff --git a/modules/openiddict/app/OpenIddict.Demo.Client.Console/Program.cs b/modules/openiddict/app/OpenIddict.Demo.Client.Console/Program.cs index 917e4b06e9..90ce819094 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Client.Console/Program.cs +++ b/modules/openiddict/app/OpenIddict.Demo.Client.Console/Program.cs @@ -1,10 +1,12 @@ using System.Net.Http.Headers; using System.Text.Json; using IdentityModel.Client; +using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; const string email = "admin@abp.io"; const string password = "1q2w3E*"; const string server = "https://localhost:44301/"; +const string serverApi = "https://localhost:44301/api/abp/application-configuration"; const string api = "https://localhost:44303/api/claims"; const string clientId = "AbpApp"; const string clientSecret = "1q2w3e*"; @@ -93,6 +95,22 @@ Console.WriteLine("Introspection : {0}", JsonSerializer.Serialize(JsonDocument.P })); Console.WriteLine(); +var serverRequest = new HttpRequestMessage(HttpMethod.Get, serverApi); +serverRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenResponse.AccessToken); + +var serverResponse = await client.SendAsync(serverRequest); +serverResponse.EnsureSuccessStatusCode(); + +var dto = JsonSerializer.Deserialize(await serverResponse.Content.ReadAsStringAsync(), new JsonSerializerOptions() +{ + PropertyNamingPolicy = JsonNamingPolicy.CamelCase +}); +Console.WriteLine("Server API response: {0}", JsonSerializer.Serialize(dto.CurrentUser, new JsonSerializerOptions +{ + WriteIndented = true +})); + +Console.WriteLine(); var request = new HttpRequestMessage(HttpMethod.Get, api); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenResponse.AccessToken); @@ -107,6 +125,7 @@ Console.WriteLine("API response: {0}", JsonSerializer.Serialize(JsonDocument.Par Console.WriteLine(); +client = new HttpClient(); tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest { diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj b/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj index 5ec9575ad3..b55295d2ec 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj +++ b/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj @@ -65,6 +65,9 @@ + + + runtime; build; native; contentfiles; analyzers diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddictServerModule.cs b/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddictServerModule.cs index 652510ab55..903779b70f 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddictServerModule.cs +++ b/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddictServerModule.cs @@ -1,7 +1,9 @@ using System.Text; +using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using OpenIddict.Demo.Server.EntityFrameworkCore; +using OpenIddict.Validation.AspNetCore; using Volo.Abp; using Volo.Abp.Account; using Volo.Abp.Account.Web; @@ -89,12 +91,33 @@ public class OpenIddictServerModule : AbpModule PreConfigure(options => { options.EnableWildcardDomainSupport = true; - options.WildcardDomainFormat = "https://{0}.abp.io/signin-oidc"; + options.WildcardDomainsFormat.Add("https://{0}.abp.io/signin-oidc"); + }); + + PreConfigure(builder => + { + builder.AddValidation(options => + { + options.AddAudiences("AbpAPIResource"); + + options.UseLocalServer(); + + options.UseAspNetCore(); + }); }); } public override void ConfigureServices(ServiceConfigurationContext context) { + // This is work for the OpenIddictServerBuilder.AddValidation() + context.Services.ConfigureApplicationCookie(options => + { + options.ForwardDefaultSelector = ctx => ctx.Request.Path.StartsWithSegments("/api") + ? OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme + : null; + }); + + Configure(options => { options.AddDevelopmentEncryptionAndSigningCertificate = false; diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/Program.cs b/modules/openiddict/app/OpenIddict.Demo.Server/Program.cs index a990d3dbc5..a03fbe6908 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/Program.cs +++ b/modules/openiddict/app/OpenIddict.Demo.Server/Program.cs @@ -30,18 +30,19 @@ builder.Services.Configure(options => options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文")); }); -builder.Services.AddAuthentication() - .AddJwtBearer(options => - { - options.Authority = "https://localhost:44301"; - options.Audience = "AbpAPIResource"; - - options.MapInboundClaims = false; - - // See OpenIddictServerModule`s PreConfigureServices method. - options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Abp_OpenIddict_Demo_C40DBB176E78")); - options.TokenValidationParameters.TokenDecryptionKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Abp_OpenIddict_Demo_87E33FC57D80")); - }); +// Use Microsoft.AspNetCore.Authentication.JwtBearer instead of OpenIddict.Validation.AspNetCore +// builder.Services.AddAuthentication() +// .AddJwtBearer(options => +// { +// options.Authority = "https://localhost:44301"; +// options.Audience = "AbpAPIResource"; +// +// options.MapInboundClaims = false; +// +// // See OpenIddictServerModule`s PreConfigureServices method. +// options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Abp_OpenIddict_Demo_C40DBB176E78")); +// options.TokenValidationParameters.TokenDecryptionKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Abp_OpenIddict_Demo_87E33FC57D80")); +// }); await builder.AddApplicationAsync(); @@ -68,7 +69,9 @@ app.UseStaticFiles(); app.UseRouting(); app.UseCors(); -app.UseJwtTokenMiddleware(); +// Use Microsoft.AspNetCore.Authentication.JwtBearer instead of OpenIddict.Validation.AspNetCore +//app.UseJwtTokenMiddleware(); + app.UseAuthentication(); app.UseMultiTenancy(); app.UseAuthorization(); diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs index ea8d75454e..250b52d959 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs @@ -4,7 +4,6 @@ using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.Modularity; -using Volo.Abp.MultiTenancy; namespace Volo.Abp.OpenIddict; @@ -32,11 +31,6 @@ public class AbpOpenIddictAspNetCoreModule : AbpModule public override void ConfigureServices(ServiceConfigurationContext context) { - Configure(options => - { - options.TenantResolvers.Insert(0, new AbpOpenIddictTenantResolveContributor()); - }); - Configure(options => { options.ClaimDestinationsProvider.Add(); diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictTenantResolveContributor.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictTenantResolveContributor.cs deleted file mode 100644 index 4869b2e520..0000000000 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictTenantResolveContributor.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Security.Principal; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using OpenIddict.Server.AspNetCore; -using Volo.Abp.AspNetCore.MultiTenancy; -using Volo.Abp.MultiTenancy; -using Volo.Abp.Users; - -namespace Volo.Abp.OpenIddict; - -public class AbpOpenIddictTenantResolveContributor : HttpTenantResolveContributorBase -{ - public const string ContributorName = "AbpOpenIddict"; - - public override string Name => ContributorName; - - protected async override Task GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext) - { - if (context.ServiceProvider.GetRequiredService().IsAuthenticated) - { - return null; - } - - if (httpContext.GetOpenIddictServerRequest() != null) - { - context.Handled = true; - var principal = (await httpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal; - return principal?.FindTenantId().ToString(); - } - - return null; - } -} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpDefaultOpenIddictClaimDestinationsProvider.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpDefaultOpenIddictClaimDestinationsProvider.cs index ba40101a1f..7f54cd81aa 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpDefaultOpenIddictClaimDestinationsProvider.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpDefaultOpenIddictClaimDestinationsProvider.cs @@ -12,12 +12,17 @@ public class AbpDefaultOpenIddictClaimDestinationsProvider : IAbpOpenIddictClaim { public virtual Task SetDestinationsAsync(AbpOpenIddictClaimDestinationsProviderContext context) { + var securityStampClaimType = context + .ScopeServiceProvider + .GetRequiredService>().Value + .ClaimsIdentity.SecurityStampClaimType; + foreach (var claim in context.Claims) { if (claim.Type == AbpClaimTypes.TenantId) { claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken, OpenIddictConstants.Destinations.IdentityToken); - return Task.CompletedTask; + continue; } switch (claim.Type) @@ -26,7 +31,7 @@ public class AbpDefaultOpenIddictClaimDestinationsProvider : IAbpOpenIddictClaim claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken); if (context.Principal.HasScope(OpenIddictConstants.Scopes.Profile)) { - claim.SetDestinations(OpenIddictConstants.Destinations.IdentityToken); + claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken, OpenIddictConstants.Destinations.IdentityToken); } break; @@ -34,7 +39,7 @@ public class AbpDefaultOpenIddictClaimDestinationsProvider : IAbpOpenIddictClaim claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken); if (context.Principal.HasScope(OpenIddictConstants.Scopes.Email)) { - claim.SetDestinations(OpenIddictConstants.Destinations.IdentityToken); + claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken, OpenIddictConstants.Destinations.IdentityToken); } break; @@ -42,17 +47,12 @@ public class AbpDefaultOpenIddictClaimDestinationsProvider : IAbpOpenIddictClaim claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken); if (context.Principal.HasScope(OpenIddictConstants.Scopes.Roles)) { - claim.SetDestinations(OpenIddictConstants.Destinations.IdentityToken); + claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken, OpenIddictConstants.Destinations.IdentityToken); } break; default: // Never include the security stamp in the access and identity tokens, as it's a secret value. - var securityStampClaimType = context - .ScopeServiceProvider - .GetRequiredService>().Value - .ClaimsIdentity.SecurityStampClaimType; - if (claim.Type != securityStampClaimType) { claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken); diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.AuthorizationCode.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.AuthorizationCode.cs index 20c7fbd10a..26018f5423 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.AuthorizationCode.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.AuthorizationCode.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Security.Principal; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc; @@ -13,38 +14,40 @@ public partial class TokenController { // Retrieve the claims principal stored in the authorization code/device code/refresh token. var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal; - - // Retrieve the user profile corresponding to the authorization code/refresh token. - // Note: if you want to automatically invalidate the authorization code/refresh token - // when the user password/roles change, use the following line instead: - // var user = _signInManager.ValidateSecurityStampAsync(info.Principal); - var user = await UserManager.GetUserAsync(principal); - if (user == null) + using (CurrentTenant.Change(principal.FindTenantId())) { - return Forbid( - authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, - properties: new AuthenticationProperties(new Dictionary - { - [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, - [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." - })); - } + // Retrieve the user profile corresponding to the authorization code/refresh token. + // Note: if you want to automatically invalidate the authorization code/refresh token + // when the user password/roles change, use the following line instead: + // var user = _signInManager.ValidateSecurityStampAsync(info.Principal); + var user = await UserManager.GetUserAsync(principal); + if (user == null) + { + return Forbid( + authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, + properties: new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." + })); + } - // Ensure the user is still allowed to sign in. - if (!await SignInManager.CanSignInAsync(user)) - { - return Forbid( - authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, - properties: new AuthenticationProperties(new Dictionary - { - [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, - [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." - })); - } + // Ensure the user is still allowed to sign in. + if (!await SignInManager.CanSignInAsync(user)) + { + return Forbid( + authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, + properties: new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." + })); + } - await SetClaimsDestinationsAsync(principal); + await SetClaimsDestinationsAsync(principal); - // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. - return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. + return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + } } } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.DeviceCode.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.DeviceCode.cs index 3d45326e4a..c46ee5eef0 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.DeviceCode.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.DeviceCode.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Security.Principal; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc; @@ -13,38 +14,40 @@ public partial class TokenController { // Retrieve the claims principal stored in the authorization code/device code/refresh token. var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal; - - // Retrieve the user profile corresponding to the authorization code/refresh token. - // Note: if you want to automatically invalidate the authorization code/refresh token - // when the user password/roles change, use the following line instead: - // var user = _signInManager.ValidateSecurityStampAsync(info.Principal); - var user = await UserManager.GetUserAsync(principal); - if (user == null) + using (CurrentTenant.Change(principal.FindTenantId())) { - return Forbid( - authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, - properties: new AuthenticationProperties(new Dictionary - { - [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, - [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." - })); - } + // Retrieve the user profile corresponding to the authorization code/refresh token. + // Note: if you want to automatically invalidate the authorization code/refresh token + // when the user password/roles change, use the following line instead: + // var user = _signInManager.ValidateSecurityStampAsync(info.Principal); + var user = await UserManager.GetUserAsync(principal); + if (user == null) + { + return Forbid( + authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, + properties: new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." + })); + } - // Ensure the user is still allowed to sign in. - if (!await SignInManager.CanSignInAsync(user)) - { - return Forbid( - authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, - properties: new AuthenticationProperties(new Dictionary - { - [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, - [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." - })); - } + // Ensure the user is still allowed to sign in. + if (!await SignInManager.CanSignInAsync(user)) + { + return Forbid( + authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, + properties: new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." + })); + } - await SetClaimsDestinationsAsync(principal); + await SetClaimsDestinationsAsync(principal); - // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. - return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. + return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + } } } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.RefreshToken.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.RefreshToken.cs index 8de5381264..05bf247ca5 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.RefreshToken.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.RefreshToken.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Security.Principal; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc; @@ -13,38 +14,40 @@ public partial class TokenController { // Retrieve the claims principal stored in the authorization code/device code/refresh token. var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal; - - // Retrieve the user profile corresponding to the authorization code/refresh token. - // Note: if you want to automatically invalidate the authorization code/refresh token - // when the user password/roles change, use the following line instead: - // var user = _signInManager.ValidateSecurityStampAsync(info.Principal); - var user = await UserManager.GetUserAsync(principal); - if (user == null) + using (CurrentTenant.Change(principal.FindTenantId())) { - return Forbid( - authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, - properties: new AuthenticationProperties(new Dictionary - { - [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, - [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." - })); - } + // Retrieve the user profile corresponding to the authorization code/refresh token. + // Note: if you want to automatically invalidate the authorization code/refresh token + // when the user password/roles change, use the following line instead: + // var user = _signInManager.ValidateSecurityStampAsync(info.Principal); + var user = await UserManager.GetUserAsync(principal); + if (user == null) + { + return Forbid( + authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, + properties: new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." + })); + } - // Ensure the user is still allowed to sign in. - if (!await SignInManager.CanSignInAsync(user)) - { - return Forbid( - authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, - properties: new AuthenticationProperties(new Dictionary - { - [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, - [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." - })); - } + // Ensure the user is still allowed to sign in. + if (!await SignInManager.CanSignInAsync(user)) + { + return Forbid( + authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, + properties: new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." + })); + } - await SetClaimsDestinationsAsync(principal); + await SetClaimsDestinationsAsync(principal); - // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. - return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. + return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + } } } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo.Abp.OpenIddict.Domain.csproj b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo.Abp.OpenIddict.Domain.csproj index 3881808934..be09cfb7e9 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo.Abp.OpenIddict.Domain.csproj +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo.Abp.OpenIddict.Domain.csproj @@ -15,7 +15,7 @@ - + diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/WildcardDomains/AbpOpenIddictWildcardDomainBase.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/WildcardDomains/AbpOpenIddictWildcardDomainBase.cs index caa4bb7381..2a603b8f44 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/WildcardDomains/AbpOpenIddictWildcardDomainBase.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/WildcardDomains/AbpOpenIddictWildcardDomainBase.cs @@ -26,15 +26,21 @@ public abstract class AbpOpenIddictWildcardDomainBase : IOpe protected virtual Task CheckWildcardDomainAsync(string url) { - var extractResult = FormattedStringValueExtracter.Extract(url, WildcardDomainOptions.WildcardDomainFormat, ignoreCase: true); - if (extractResult.IsMatch) + foreach (var domainFormat in WildcardDomainOptions.WildcardDomainsFormat) { - return Task.FromResult(true); + var extractResult = FormattedStringValueExtracter.Extract(url, domainFormat, ignoreCase: true); + if (extractResult.IsMatch) + { + return Task.FromResult(true); + } } - if (WildcardDomainOptions.WildcardDomainFormat.Replace("{0}.", "").IndexOf(url, StringComparison.OrdinalIgnoreCase) > 1) + foreach (var domainFormat in WildcardDomainOptions.WildcardDomainsFormat) { - return Task.FromResult(true); + if (domainFormat.Replace("{0}.", "").Equals(url, StringComparison.OrdinalIgnoreCase)) + { + return Task.FromResult(true); + } } return Task.FromResult(false); diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/WildcardDomains/AbpOpenIddictWildcardDomainOptions.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/WildcardDomains/AbpOpenIddictWildcardDomainOptions.cs index 91e290c595..5b0e8f591a 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/WildcardDomains/AbpOpenIddictWildcardDomainOptions.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/WildcardDomains/AbpOpenIddictWildcardDomainOptions.cs @@ -1,8 +1,16 @@ -namespace Volo.Abp.OpenIddict.WildcardDomains; +using System.Collections.Generic; + +namespace Volo.Abp.OpenIddict.WildcardDomains; public class AbpOpenIddictWildcardDomainOptions { public bool EnableWildcardDomainSupport { get; set; } - public string WildcardDomainFormat { get; set; } + public HashSet WildcardDomainsFormat { get; } + + public AbpOpenIddictWildcardDomainOptions() + { + WildcardDomainsFormat = new HashSet(); + } + }