From f766e84e074c7f959fc35bd6b6a376b099fd341a Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 1 Apr 2022 20:50:37 +0800 Subject: [PATCH] Add `IAbpOpenIddictClaimDestinationsProvider`. --- .../app/OpenIddict.Demo.Server/Program.cs | 11 ++++ ...p.OpenIddict.AspNetCore.csproj.DotSettings | 2 + .../AbpOpenIddictAspNetCoreModule.cs | 5 ++ ...aultOpenIddictClaimDestinationsProvider.cs | 66 +++++++++++++++++++ .../AbpOpenIddictClaimDestinationsOptions.cs | 13 ++++ ...nIddictClaimDestinationsProviderContext.cs | 20 ++++++ ...IAbpOpenIddictClaimDestinationsProvider.cs | 8 +++ ...Base.cs => AbpOpenIdDictControllerBase.cs} | 63 ++++-------------- .../Controllers/AuthorizeController.cs | 12 +--- .../Controllers/LogoutController.cs | 4 +- .../TokenController.AuthorizationCode.cs | 6 +- .../Controllers/TokenController.DeviceCode.cs | 5 +- .../Controllers/TokenController.Password.cs | 41 ++++++------ .../TokenController.RefreshToken.cs | 5 +- .../OpenIddict/Controllers/TokenController.cs | 2 +- .../Controllers/UserInfoController.cs | 2 +- .../Views/Authorize/Authorize.cshtml | 11 ++-- .../Abp/OpenIddict/Views/Logout/Logout.cshtml | 10 +-- .../Volo.Abp.OpenIddict.Domain.Shared.csproj | 1 + .../AbpOpenIddictDomainSharedModule.cs | 7 +- .../Localization/OpenIddict/en.json | 7 +- .../Localization/OpenIddict/zh-Hans.json | 37 ++++++----- .../Localization/OpenIddict/zh-Hant.json | 25 ++++--- 23 files changed, 225 insertions(+), 138 deletions(-) create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo.Abp.OpenIddict.AspNetCore.csproj.DotSettings create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpDefaultOpenIddictClaimDestinationsProvider.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsOptions.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsProviderContext.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/IAbpOpenIddictClaimDestinationsProvider.cs rename modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/{OpenIdDictControllerBase.cs => AbpOpenIdDictControllerBase.cs} (50%) diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/Program.cs b/modules/openiddict/app/OpenIddict.Demo.Server/Program.cs index d3cef1792e..5cf7cb6d6c 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/Program.cs +++ b/modules/openiddict/app/OpenIddict.Demo.Server/Program.cs @@ -1,4 +1,5 @@ using OpenIddict.Demo.Server; +using Volo.Abp.Localization; using Volo.Abp.OpenIddict.Jwt; using Volo.Abp.Users; @@ -19,6 +20,14 @@ builder.Logging.ClearProviders(); builder.Logging.AddConsole(); builder.Host.UseAutofac(); +builder.Services.Configure(options => +{ + options.Languages.Add(new LanguageInfo("en", "en", "English")); + options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe")); + options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文")); +}); + builder.Services.AddAuthentication() .AddJwtBearer(options => { @@ -33,6 +42,8 @@ await builder.AddApplicationAsync(); var app = builder.Build(); await app.InitializeApplicationAsync(); +app.UseAbpRequestLocalization(); + // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo.Abp.OpenIddict.AspNetCore.csproj.DotSettings b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo.Abp.OpenIddict.AspNetCore.csproj.DotSettings new file mode 100644 index 0000000000..f9562c2c08 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo.Abp.OpenIddict.AspNetCore.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file 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 59dbaf9497..f614b39249 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 @@ -41,6 +41,11 @@ public class AbpOpenIddictAspNetCoreModule : AbpModule options.TenantResolvers.Insert(0, new AbpOpenIddictTenantResolveContributor()); }); + Configure(options => + { + options.ClaimDestinationsProvider.Add(); + }); + Configure(options => { options.ViewLocationFormats.Add("/Volo/Abp/OpenIddict/Views/{1}/{0}.cshtml"); 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 new file mode 100644 index 0000000000..ba40101a1f --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpDefaultOpenIddictClaimDestinationsProvider.cs @@ -0,0 +1,66 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using OpenIddict.Abstractions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Security.Claims; + +namespace Volo.Abp.OpenIddict; + +public class AbpDefaultOpenIddictClaimDestinationsProvider : IAbpOpenIddictClaimDestinationsProvider, ITransientDependency +{ + public virtual Task SetDestinationsAsync(AbpOpenIddictClaimDestinationsProviderContext context) + { + foreach (var claim in context.Claims) + { + if (claim.Type == AbpClaimTypes.TenantId) + { + claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken, OpenIddictConstants.Destinations.IdentityToken); + return Task.CompletedTask; + } + + switch (claim.Type) + { + case OpenIddictConstants.Claims.Name: + claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken); + if (context.Principal.HasScope(OpenIddictConstants.Scopes.Profile)) + { + claim.SetDestinations(OpenIddictConstants.Destinations.IdentityToken); + } + break; + + case OpenIddictConstants.Claims.Email: + claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken); + if (context.Principal.HasScope(OpenIddictConstants.Scopes.Email)) + { + claim.SetDestinations(OpenIddictConstants.Destinations.IdentityToken); + } + break; + + case OpenIddictConstants.Claims.Role: + claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken); + if (context.Principal.HasScope(OpenIddictConstants.Scopes.Roles)) + { + claim.SetDestinations(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); + } + break; + } + } + + return Task.CompletedTask; + } +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsOptions.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsOptions.cs new file mode 100644 index 0000000000..e6094dbc03 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsOptions.cs @@ -0,0 +1,13 @@ +using Volo.Abp.Collections; + +namespace Volo.Abp.OpenIddict; + +public class AbpOpenIddictClaimDestinationsOptions +{ + public ITypeList ClaimDestinationsProvider { get; } + + public AbpOpenIddictClaimDestinationsOptions() + { + ClaimDestinationsProvider = new TypeList(); + } +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsProviderContext.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsProviderContext.cs new file mode 100644 index 0000000000..ff5d993e95 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsProviderContext.cs @@ -0,0 +1,20 @@ +using System; +using System.Security.Claims; + +namespace Volo.Abp.OpenIddict; + +public class AbpOpenIddictClaimDestinationsProviderContext +{ + public IServiceProvider ScopeServiceProvider { get; } + + public ClaimsPrincipal Principal{ get;} + + public Claim[] Claims { get; } + + public AbpOpenIddictClaimDestinationsProviderContext(IServiceProvider scopeServiceProvider, ClaimsPrincipal principal, Claim[] claims) + { + ScopeServiceProvider = scopeServiceProvider; + Principal = principal; + Claims = claims; + } +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/IAbpOpenIddictClaimDestinationsProvider.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/IAbpOpenIddictClaimDestinationsProvider.cs new file mode 100644 index 0000000000..e499545163 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/IAbpOpenIddictClaimDestinationsProvider.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.OpenIddict; + +public interface IAbpOpenIddictClaimDestinationsProvider +{ + Task SetDestinationsAsync(AbpOpenIddictClaimDestinationsProviderContext context); +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/OpenIdDictControllerBase.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AbpOpenIdDictControllerBase.cs similarity index 50% rename from modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/OpenIdDictControllerBase.cs rename to modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AbpOpenIdDictControllerBase.cs index 13ec3bd996..055428093b 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/OpenIdDictControllerBase.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AbpOpenIdDictControllerBase.cs @@ -7,6 +7,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using OpenIddict.Abstractions; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Identity; @@ -16,7 +18,7 @@ using IdentityUser = Volo.Abp.Identity.IdentityUser; namespace Volo.Abp.OpenIddict.Controllers; -public abstract class OpenIdDictControllerBase : AbpController +public abstract class AbpOpenIdDictControllerBase : AbpController { protected SignInManager SignInManager => LazyServiceProvider.LazyGetRequiredService>(); protected IdentityUserManager UserManager => LazyServiceProvider.LazyGetRequiredService(); @@ -24,13 +26,13 @@ public abstract class OpenIdDictControllerBase : AbpController protected IOpenIddictAuthorizationManager AuthorizationManager => LazyServiceProvider.LazyGetRequiredService(); protected IOpenIddictScopeManager ScopeManager => LazyServiceProvider.LazyGetRequiredService(); protected IOpenIddictTokenManager TokenManager => LazyServiceProvider.LazyGetRequiredService(); + protected IOptions OpenIddictClaimDestinationsOptions => LazyServiceProvider.LazyGetRequiredService>(); - protected OpenIdDictControllerBase() + protected AbpOpenIdDictControllerBase() { LocalizationResource = typeof(AbpOpenIddictResource); } - protected virtual Task GetOpenIddictServerRequest(HttpContext httpContext) { var request = HttpContext.GetOpenIddictServerRequest() ?? @@ -54,56 +56,15 @@ public abstract class OpenIdDictControllerBase : AbpController return resources; } - protected virtual IEnumerable GetDestinations(Claim claim, ClaimsPrincipal principal) + protected virtual async Task SetClaimsDestinationsAsync(ClaimsPrincipal principal) { - // Note: by default, claims are NOT automatically included in the access and identity tokens. - // To allow OpenIddict to serialize them, you must attach them a destination, that specifies - // whether they should be included in access tokens, in identity tokens or in both. - - if (claim.Type == AbpClaimTypes.TenantId) - { - yield return OpenIddictConstants.Destinations.AccessToken; - yield return OpenIddictConstants.Destinations.IdentityToken; - } - - switch (claim.Type) + using (var scope = LazyServiceProvider.LazyGetRequiredService().CreateScope()) { - case OpenIddictConstants.Claims.Name: - yield return OpenIddictConstants.Destinations.AccessToken; - - if (principal.HasScope(OpenIddictConstants.Scopes.Profile)) - { - yield return OpenIddictConstants.Destinations.IdentityToken; - } - - yield break; - - case OpenIddictConstants.Claims.Email: - yield return OpenIddictConstants.Destinations.AccessToken; - - if (principal.HasScope(OpenIddictConstants.Scopes.Email)) - { - yield return OpenIddictConstants.Destinations.IdentityToken; - } - - yield break; - - case OpenIddictConstants.Claims.Role: - yield return OpenIddictConstants.Destinations.AccessToken; - - if (principal.HasScope(OpenIddictConstants.Scopes.Roles)) - { - yield return OpenIddictConstants.Destinations.IdentityToken; - } - - yield break; - - // Never include the security stamp in the access and identity tokens, as it's a secret value. - case "AspNet.Identity.SecurityStamp": yield break; - - default: - yield return OpenIddictConstants.Destinations.AccessToken; - yield break; + foreach (var providerType in OpenIddictClaimDestinationsOptions.Value.ClaimDestinationsProvider) + { + var provider = (IAbpOpenIddictClaimDestinationsProvider)scope.ServiceProvider.GetRequiredService(providerType); + await provider.SetDestinationsAsync(new AbpOpenIddictClaimDestinationsProviderContext(scope.ServiceProvider, principal, principal.Claims.ToArray())); + } } } } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AuthorizeController.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AuthorizeController.cs index 6b676a71b5..a3cf2ccb64 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AuthorizeController.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AuthorizeController.cs @@ -16,7 +16,7 @@ using Volo.Abp.OpenIddict.ViewModels.Authorization; namespace Volo.Abp.OpenIddict.Controllers; [Route("connect/authorize")] -public class AuthorizeController : OpenIdDictControllerBase +public class AuthorizeController : AbpOpenIdDictControllerBase { [HttpGet, HttpPost] [IgnoreAntiforgeryToken] @@ -132,10 +132,7 @@ public class AuthorizeController : OpenIdDictControllerBase principal.SetAuthorizationId(await AuthorizationManager.GetIdAsync(authorization)); - foreach (var claim in principal.Claims) - { - claim.SetDestinations(GetDestinations(claim, principal)); - } + await SetClaimsDestinationsAsync(principal); return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); @@ -222,10 +219,7 @@ public class AuthorizeController : OpenIdDictControllerBase principal.SetScopes(request.GetScopes()); principal.SetResources(await GetResourcesAsync(request.GetScopes())); - foreach (var claim in principal.Claims) - { - claim.SetDestinations(GetDestinations(claim, principal)); - } + await SetClaimsDestinationsAsync(principal); // 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/LogoutController.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/LogoutController.cs index e3008e8f67..202a4f7483 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/LogoutController.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/LogoutController.cs @@ -6,7 +6,7 @@ using OpenIddict.Server.AspNetCore; namespace Volo.Abp.OpenIddict.Controllers; [Route("connect/logout")] -public class LogoutController : OpenIdDictControllerBase +public class LogoutController : AbpOpenIdDictControllerBase { [HttpGet] public virtual Task GetAsync() @@ -15,7 +15,7 @@ public class LogoutController : OpenIdDictControllerBase } [HttpPost] - public virtual async Task PostAsync() + public virtual async Task HandleAcceptAsync() { // Ask ASP.NET Core Identity to delete the local and external cookies created // when the user agent is redirected from the external identity provider 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 eb615656d8..1ca6263888 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.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc; @@ -42,10 +43,7 @@ public partial class TokenController })); } - foreach (var claim in principal.Claims) - { - claim.SetDestinations(GetDestinations(claim, principal)); - } + await SetClaimsDestinationsAsync(principal); // 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 f577dd19f9..857fbe55e6 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 @@ -42,10 +42,7 @@ public partial class TokenController })); } - foreach (var claim in principal.Claims) - { - claim.SetDestinations(GetDestinations(claim, principal)); - } + await SetClaimsDestinationsAsync(principal); // 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.Password.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs index 493056b029..c8a62abd85 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs @@ -27,7 +27,7 @@ public partial class TokenController protected IOptions AbpIdentityOptions => LazyServiceProvider.LazyGetRequiredService>(); protected IOptions IdentityOptions => LazyServiceProvider.LazyGetRequiredService>(); protected IdentitySecurityLogManager IdentitySecurityLogManager => LazyServiceProvider.LazyGetRequiredService(); - + [UnitOfWork] protected virtual async Task HandlePasswordAsync(OpenIddictRequest request) { @@ -64,20 +64,20 @@ public partial class TokenController } } } - + await IdentityOptions.SetAsync(); - + user = await UserManager.FindByNameAsync(request.Username); if (user == null) { Logger.LogInformation("No user found matching username: {username}", request.Username); - + var properties = new AuthenticationProperties(new Dictionary { [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = L["InvalidUsername"] }); - + await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext() { Identity = OpenIddictSecurityLogIdentityConsts.OpenIddict, @@ -88,7 +88,7 @@ public partial class TokenController return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); } - + var result = await SignInManager.CheckPasswordSignInAsync(user, request.Password, true); if (!result.Succeeded) { @@ -108,7 +108,7 @@ public partial class TokenController Logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials", request.Username); errorDescription = L["InvalidUserNameOrPassword"]; } - + var properties = new AuthenticationProperties(new Dictionary { [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, @@ -117,7 +117,7 @@ public partial class TokenController return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); } - + if (await IsTfaEnabledAsync(user)) { return await HandleTwoFactorLoginAsync(request, user); @@ -130,12 +130,12 @@ public partial class TokenController UserName = request.Username, ClientId = request.ClientId }); - + return await SetSuccessResultAsync(request, user); } } } - + protected virtual async Task ReplaceEmailToUsernameOfInputIfNeeds(OpenIddictRequest request) { if (!ValidationHelper.IsValidEmailAddress(request.Username)) @@ -157,7 +157,7 @@ public partial class TokenController request.Username = userByEmail.UserName; } - + protected virtual async Task HandleTwoFactorLoginAsync(OpenIddictRequest request, IdentityUser user) { var twoFactorProvider = request.GetParameter("TwoFactorProvider")?.ToString(); @@ -192,12 +192,12 @@ public partial class TokenController UserName = request.Username, ClientId = request.ClientId }); - + var properties = new AuthenticationProperties(new Dictionary { [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = nameof(SignInResult.RequiresTwoFactor), - + ["userId"] = user.Id.ToString("N"), ["twoFactorToken"] = twoFactorToken }); @@ -211,15 +211,12 @@ public partial class TokenController // Create a new ClaimsPrincipal containing the claims that // will be used to create an id_token, a token or a code. var principal = await SignInManager.CreateUserPrincipalAsync(user); - + principal.SetScopes(request.GetScopes()); principal.SetResources(await GetResourcesAsync(request.GetScopes())); - foreach (var claim in principal.Claims) - { - claim.SetDestinations(GetDestinations(claim, principal)); - } - + await SetClaimsDestinationsAsync(principal); + await IdentitySecurityLogManager.SaveAsync( new IdentitySecurityLogContext { @@ -229,14 +226,14 @@ public partial class TokenController ClientId = request.ClientId } ); - + return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); } - + protected virtual async Task IsTfaEnabledAsync(IdentityUser user) { return UserManager.SupportsUserTwoFactor && await UserManager.GetTwoFactorEnabledAsync(user) && (await UserManager.GetValidTwoFactorProvidersAsync(user)).Count > 0; } -} \ No newline at end of file +} 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 77fa72514e..d21aead1dd 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 @@ -42,10 +42,7 @@ public partial class TokenController })); } - foreach (var claim in principal.Claims) - { - claim.SetDestinations(GetDestinations(claim, principal)); - } + await SetClaimsDestinationsAsync(principal); // 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.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.cs index adde3c7a9f..364cce5f62 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.cs @@ -7,7 +7,7 @@ using OpenIddict.Abstractions; namespace Volo.Abp.OpenIddict.Controllers; [Route("connect/token")] -public partial class TokenController : OpenIdDictControllerBase +public partial class TokenController : AbpOpenIdDictControllerBase { [HttpGet, HttpPost, Produces("application/json")] public virtual async Task HandleAsync() diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/UserInfoController.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/UserInfoController.cs index cd210dc1c9..7ad74e2c25 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/UserInfoController.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/UserInfoController.cs @@ -13,7 +13,7 @@ namespace Volo.Abp.OpenIddict.Controllers; [Route("connect/userinfo")] [Authorize(AuthenticationSchemes = OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)] -public class UserInfoController : OpenIdDictControllerBase +public class UserInfoController : AbpOpenIdDictControllerBase { [HttpGet] [HttpPost] diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Authorize/Authorize.cshtml b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Authorize/Authorize.cshtml index 96f5597d10..31c8b1e665 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Authorize/Authorize.cshtml +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Authorize/Authorize.cshtml @@ -1,12 +1,13 @@ @using Microsoft.Extensions.Primitives -@using Microsoft.Extensions.Localization @using Volo.Abp.OpenIddict.Localization +@using Microsoft.AspNetCore.Mvc.Localization @model AuthorizeViewModel -@inject IStringLocalizer L +@inject IHtmlLocalizer L
-

Authorization

-

Do you want to grant @Model.ApplicationName access to your data? (scopes requested: @Model.Scope)

+

@L["Authorization"]

+

@string.Format(L["DoYouWantToGrantAccessToYourData"].Value, Model.ApplicationName)

+

@L["ScopesRequested"]: @Model.Scope

@Html.AntiForgeryToken() @@ -16,7 +17,7 @@ } - +
diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Logout/Logout.cshtml b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Logout/Logout.cshtml index 75c89f47db..6f0b398643 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Logout/Logout.cshtml +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Logout/Logout.cshtml @@ -1,12 +1,12 @@ @using Microsoft.Extensions.Primitives -@using Microsoft.Extensions.Localization @using Volo.Abp.OpenIddict.Localization +@using Microsoft.AspNetCore.Mvc.Localization @model AuthorizeViewModel -@inject IStringLocalizer L +@inject IHtmlLocalizer L
-

Log out

-

Are you sure you want to sign out?

+

@L["LogOut"]

+

@L["AreYouSureYouWantToSignOut"]

@Html.AntiForgeryToken() @@ -16,6 +16,6 @@ } - +
diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo.Abp.OpenIddict.Domain.Shared.csproj b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo.Abp.OpenIddict.Domain.Shared.csproj index 043ad730e4..1c1e681763 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo.Abp.OpenIddict.Domain.Shared.csproj +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo.Abp.OpenIddict.Domain.Shared.csproj @@ -11,6 +11,7 @@ + diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/AbpOpenIddictDomainSharedModule.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/AbpOpenIddictDomainSharedModule.cs index 3d3219376c..23d6705318 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/AbpOpenIddictDomainSharedModule.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/AbpOpenIddictDomainSharedModule.cs @@ -1,4 +1,5 @@ -using Volo.Abp.Modularity; +using Localization.Resources.AbpUi; +using Volo.Abp.Modularity; using Volo.Abp.Localization; using Volo.Abp.OpenIddict.Localization; using Volo.Abp.Localization.ExceptionHandling; @@ -24,8 +25,8 @@ public class AbpOpenIddictDomainSharedModule : AbpModule { options.Resources .Add("en") - .AddBaseTypes(typeof(AbpValidationResource)) - .AddVirtualJson("/Localization/OpenIddict"); + .AddBaseTypes(typeof(AbpValidationResource), typeof(AbpUiResource)) + .AddVirtualJson("Volo/Abp/OpenIddict/Localization/OpenIddict"); }); Configure(options => diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/en.json b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/en.json index 689149766a..bef8978538 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/en.json +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/en.json @@ -17,6 +17,11 @@ "TheTokenIsNoLongerValid": "The token is no longer valid.", "InteractiveUserConsentIsRequired": "Interactive user consent is required.", "TheUserIsNoLongerAllowedToSignIn": "The user is no longer allowed to sign in.", - "TheSpecifiedAccessTokenIsBoundToAnAccountThatNoLongerExists": "The specified access token is bound to an account that no longer exists." + "TheSpecifiedAccessTokenIsBoundToAnAccountThatNoLongerExists": "The specified access token is bound to an account that no longer exists.", + "Authorization": "Authorization", + "DoYouWantToGrantAccessToYourData": "Do you want to grant {0} access to your data?", + "ScopesRequested": "Scopes requested", + "LogOut": "Log out", + "AreYouSureYouWantToSignOut": "Are you sure you want to sign out?" } } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/zh-Hans.json b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/zh-Hans.json index 92413b8ac3..1bd13659fb 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/zh-Hans.json +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/zh-Hans.json @@ -1,22 +1,27 @@ { "culture": "zh-Hans", "texts": { - "UserLockedOut": "登錄失敗,用戶賬戶已被鎖定.請稍後再試.", - "InvalidUserNameOrPassword": "用戶名或密碼錯誤!", - "LoginIsNotAllowed": "無法登錄!妳的賬號未激活或者需要驗證郵箱地址/手機號.", - "InvalidUsername": "用戶名或密碼錯誤!", - "InvalidAuthenticatorCode": "驗證碼無效!", - "TheTargetUserIsNotLinkedToYou": "目標用戶未和妳有關聯!", - "TheOpenIDConnectRequestCannotBeRetrieved": "無法檢索 OpenID Connect 請求.", - "TheUserDetailsCannotBbeRetrieved" : "無法檢索用戶詳細信息.", - "TheApplicationDetailsCannotBeFound": "找不到應用詳情.", - "DetailsConcerningTheCallingClientApplicationCannotBeFound": "找不到有關調用客戶端應用程序的詳細信息.", - "TheSpecifiedGrantTypeIsNotImplemented.": "未實施指定的授權類型 {0}.", - "TheUserIsNotLoggedIn": "用戶未登錄.", - "TheLoggedInUserIsNotAllowedToAccessThisClientApplication": "登錄的用戶不允許訪問此客戶端應用程序.", + "UserLockedOut": "登录失败,用户账户已被锁定.请稍后再试.", + "InvalidUserNameOrPassword": "用户名或密码错误!", + "LoginIsNotAllowed": "无法登录!妳的账号未激活或者需要验证邮箱地址/手机号.", + "InvalidUsername": "用户名或密码错误!", + "InvalidAuthenticatorCode": "验证码无效!", + "TheTargetUserIsNotLinkedToYou": "目标用户未和妳有关联!", + "TheOpenIDConnectRequestCannotBeRetrieved": "无法检索 OpenID Connect 请求.", + "TheUserDetailsCannotBbeRetrieved" : "无法检索用户详细信息.", + "TheApplicationDetailsCannotBeFound": "找不到应用详情.", + "DetailsConcerningTheCallingClientApplicationCannotBeFound": "找不到有关调用客户端应用程序的详细信息.", + "TheSpecifiedGrantTypeIsNotImplemented.": "未实施指定的授权类型 {0}.", + "TheUserIsNotLoggedIn": "用户未登录.", + "TheLoggedInUserIsNotAllowedToAccessThisClientApplication": "登录的用户不允许访问此客户端应用程序.", "TheTokenIsNoLongerValid": "令牌不再有效.", - "InteractiveUserConsentIsRequired": "需要交互式用戶同意.", - "TheUserIsNoLongerAllowedToSignIn": "不再允許用戶登錄.", - "TheSpecifiedAccessTokenIsBoundToAnAccountThatNoLongerExists": "指定的訪問令牌綁定到不再存在的帳戶." + "InteractiveUserConsentIsRequired": "需要交互式用户同意.", + "TheUserIsNoLongerAllowedToSignIn": "不再允许用户登录.", + "TheSpecifiedAccessTokenIsBoundToAnAccountThatNoLongerExists": "指定的访问令牌绑定到不再存在的帐户.", + "Authorization": "授权", + "DoYouWantToGrantAccessToYourData": "是否要授予 {0} 访问你的数据的权限?", + "ScopesRequested": "要求的Scope", + "LogOut": "注销", + "AreYouSureYouWantToSignOut": "你确定要退出吗?" } } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/zh-Hant.json b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/zh-Hant.json index 4f15fceb88..dec975d1b3 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/zh-Hant.json +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/zh-Hant.json @@ -7,16 +7,21 @@ "InvalidUsername": "用戶名或密碼錯誤!", "InvalidAuthenticatorCode": "驗證碼無效!", "TheTargetUserIsNotLinkedToYou": "目標用戶與您無關!", - "TheOpenIDConnectRequestCannotBeRetrieved": "无法检索 OpenID Connect 请求.", - "TheUserDetailsCannotBbeRetrieved" : "无法检索用户详细信息.", - "TheApplicationDetailsCannotBeFound": "找不到应用详情.", - "DetailsConcerningTheCallingClientApplicationCannotBeFound": "找不到有关调用客户端应用程序的详细信息.", - "TheSpecifiedGrantTypeIsNotImplemented.": "未实施指定的授权类型 {0}.", - "TheUserIsNotLoggedIn": "用户未登录.", - "TheLoggedInUserIsNotAllowedToAccessThisClientApplication": "登录的用户不允许访问此客户端应用程序.", + "TheOpenIDConnectRequestCannotBeRetrieved": "無法檢索 OpenID Connect 請求.", + "TheUserDetailsCannotBbeRetrieved" : "無法檢索用戶詳細信息.", + "TheApplicationDetailsCannotBeFound": "找不到應用詳情.", + "DetailsConcerningTheCallingClientApplicationCannotBeFound": "找不到有關調用客戶端應用程序的詳細信息.", + "TheSpecifiedGrantTypeIsNotImplemented.": "未實施指定的授權類型 {0}.", + "TheUserIsNotLoggedIn": "用戶未登錄.", + "TheLoggedInUserIsNotAllowedToAccessThisClientApplication": "登錄的用戶不允許訪問此客戶端應用程序.", "TheTokenIsNoLongerValid": "令牌不再有效.", - "InteractiveUserConsentIsRequired": "需要交互式用户同意.", - "TheUserIsNoLongerAllowedToSignIn": "不再允许用户登录.", - "TheSpecifiedAccessTokenIsBoundToAnAccountThatNoLongerExists": "指定的访问令牌绑定到不再存在的帐户." + "InteractiveUserConsentIsRequired": "需要交互式用戶同意.", + "TheUserIsNoLongerAllowedToSignIn": "不再允許用戶登錄.", + "TheSpecifiedAccessTokenIsBoundToAnAccountThatNoLongerExists": "指定的訪問令牌綁定到不再存在的帳戶.", + "Authorization": "授權", + "DoYouWantToGrantAccessToYourData": "是否要授予 {0} 訪問你的數據的權限?", + "ScopesRequested": "要求的Scope", + "LogOut": "註銷", + "AreYouSureYouWantToSignOut": "你確定要退出嗎?" } }