From 11feeb3f83afdc9e52075c7c90b65c96ae7a2b3d Mon Sep 17 00:00:00 2001 From: cKey <35512826+colinin@users.noreply.github.com> Date: Fri, 14 Jan 2022 15:14:40 +0800 Subject: [PATCH] =?UTF-8?q?fix(ids):=20=E6=89=A9=E5=B1=95=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E9=AA=8C=E8=AF=81=E5=99=A8=E5=AE=9E=E7=8E=B0=E4=B9=9F?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E8=AE=B0=E5=BD=95=E5=AE=89=E5=85=A8=E6=97=A5?= =?UTF-8?q?=E5=BF=97.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SmsValidator/SmsTokenGrantValidator.cs | 90 ++++++++++++-- .../SmsValidator/SmsValidatorConsts.cs | 2 + .../WeChatMiniProgramGrantValidator.cs | 3 +- .../Official/WeChatOfficialGrantValidator.cs | 3 +- .../WeChat/WeChatGrantValidator.cs | 110 +++++++++++++++--- 5 files changed, 177 insertions(+), 31 deletions(-) diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsTokenGrantValidator.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsTokenGrantValidator.cs index 81465bcdb..2452a4d0f 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsTokenGrantValidator.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsTokenGrantValidator.cs @@ -3,20 +3,22 @@ using IdentityServer4.Events; using IdentityServer4.Models; using IdentityServer4.Services; using IdentityServer4.Validation; -using LINGYUN.Abp.Identity; using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; +using Volo.Abp.Identity; +using Volo.Abp.IdentityServer; using Volo.Abp.IdentityServer.Localization; using Volo.Abp.Security.Claims; -using IdentityUser = Volo.Abp.Identity.IdentityUser; -using IdentityResource = Volo.Abp.Identity.Localization.IdentityResource; +using IdentityResource = Volo.Abp.Identity.Localization.IdentityResource; +using IdentityUser = Volo.Abp.Identity.IdentityUser; +using IIdentityUserRepository = LINGYUN.Abp.Identity.IIdentityUserRepository; + namespace LINGYUN.Abp.IdentityServer.SmsValidator { public class SmsTokenGrantValidator : IExtensionGrantValidator @@ -25,6 +27,7 @@ namespace LINGYUN.Abp.IdentityServer.SmsValidator protected IEventService EventService { get; } protected IIdentityUserRepository UserRepository { get; } protected UserManager UserManager { get; } + protected IdentitySecurityLogManager IdentitySecurityLogManager { get; } protected IStringLocalizer IdentityLocalizer { get; } protected IStringLocalizer IdentityServerLocalizer { get; } @@ -32,6 +35,7 @@ namespace LINGYUN.Abp.IdentityServer.SmsValidator IEventService eventService, UserManager userManager, IIdentityUserRepository userRepository, + IdentitySecurityLogManager identitySecurityLogManager, IStringLocalizer identityLocalizer, IStringLocalizer identityServerLocalizer, ILogger logger) @@ -40,6 +44,7 @@ namespace LINGYUN.Abp.IdentityServer.SmsValidator EventService = eventService; UserManager = userManager; UserRepository = userRepository; + IdentitySecurityLogManager = identitySecurityLogManager; IdentityLocalizer = identityLocalizer; IdentityServerLocalizer = identityServerLocalizer; } @@ -76,6 +81,9 @@ namespace LINGYUN.Abp.IdentityServer.SmsValidator { Logger.LogInformation("Authentication failed for username: {username}, reason: locked out", currentUser.UserName); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityLocalizer["Volo.Abp.Identity:UserLockedOut"]); + + await SaveSecurityLogAsync(context, currentUser, IdentityServerSecurityLogActionConsts.LoginLockedout); + return; } @@ -97,22 +105,80 @@ namespace LINGYUN.Abp.IdentityServer.SmsValidator context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, userAccessFailedError); await EventService.RaiseAsync(new UserLoginFailureEvent(currentUser.UserName, userAccessFailedError, false)); } - return; - } - var sub = await UserManager.GetUserIdAsync(currentUser); + await SaveSecurityLogAsync(context, currentUser, SmsValidatorConsts.SecurityCodeFailed); - var additionalClaims = new List(); - if (currentUser.TenantId.HasValue) - { - additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString())); + return; } await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, phoneNumber, null)); - context.Result = new GrantValidationResult(sub, OidcConstants.AuthenticationMethods.ConfirmationBySms, additionalClaims.ToArray()); // 登录之后需要更新安全令牌 (await UserManager.UpdateSecurityStampAsync(currentUser)).CheckErrors(); + + await SetSuccessResultAsync(context, currentUser); + } + + protected virtual async Task SetSuccessResultAsync(ExtensionGrantValidationContext context, IdentityUser user) + { + var sub = await UserManager.GetUserIdAsync(user); + + Logger.LogInformation("Credentials validated for username: {username}", user.UserName); + + var additionalClaims = new List(); + + await AddCustomClaimsAsync(additionalClaims, user, context); + + context.Result = new GrantValidationResult( + sub, + OidcConstants.AuthenticationMethods.ConfirmationBySms, + additionalClaims.ToArray() + ); + + await SaveSecurityLogAsync( + context, + user, + IdentityServerSecurityLogActionConsts.LoginSucceeded); + } + + protected virtual async Task SaveSecurityLogAsync( + ExtensionGrantValidationContext context, + IdentityUser user, + string action) + { + var logContext = new IdentitySecurityLogContext + { + Identity = IdentityServerSecurityLogIdentityConsts.IdentityServer, + Action = action, + UserName = user.UserName, + ClientId = await FindClientIdAsync(context) + }; + logContext.WithProperty("GrantType", GrantType); + + await IdentitySecurityLogManager.SaveAsync(logContext); + } + + protected virtual Task FindClientIdAsync(ExtensionGrantValidationContext context) + { + return Task.FromResult(context.Request?.Client?.ClientId); + } + + protected virtual Task AddCustomClaimsAsync( + List customClaims, + IdentityUser user, + ExtensionGrantValidationContext context) + { + if (user.TenantId.HasValue) + { + customClaims.Add( + new Claim( + AbpClaimTypes.TenantId, + user.TenantId?.ToString() + ) + ); + } + + return Task.CompletedTask; } } } diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsValidatorConsts.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsValidatorConsts.cs index 91ff74fb0..1c404fc2e 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsValidatorConsts.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/SmsValidator/SmsValidatorConsts.cs @@ -9,5 +9,7 @@ public const string SmsValidatorTokenName = "phone_verify_code"; public const string SmsValidatorPurpose = "phone_verify"; + + public const string SecurityCodeFailed = "SecurityCodeFailed"; } } diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/MiniProgram/WeChatMiniProgramGrantValidator.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/MiniProgram/WeChatMiniProgramGrantValidator.cs index 78f81a243..3a2201016 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/MiniProgram/WeChatMiniProgramGrantValidator.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/MiniProgram/WeChatMiniProgramGrantValidator.cs @@ -37,11 +37,12 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.MiniProgram IWeChatOpenIdFinder weChatOpenIdFinder, UserManager userManager, IIdentityUserRepository userRepository, + IdentitySecurityLogManager identitySecurityLogManager, IStringLocalizer identityLocalizer, IStringLocalizer identityServerLocalizer, IStringLocalizer wechatLocalizer, AbpWeChatMiniProgramOptionsFactory miniProgramOptionsFactory) - : base(eventService, weChatOpenIdFinder, userManager, userRepository, identityLocalizer, identityServerLocalizer) + : base(eventService, weChatOpenIdFinder, userManager, userRepository, identitySecurityLogManager, identityLocalizer, identityServerLocalizer) { WeChatLocalizer = wechatLocalizer; MiniProgramOptionsFactory = miniProgramOptionsFactory; diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialGrantValidator.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialGrantValidator.cs index 690e0b456..956b9432d 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialGrantValidator.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/Official/WeChatOfficialGrantValidator.cs @@ -37,11 +37,12 @@ namespace LINGYUN.Abp.IdentityServer.WeChat.Official IWeChatOpenIdFinder weChatOpenIdFinder, UserManager userManager, IIdentityUserRepository userRepository, + IdentitySecurityLogManager identitySecurityLogManager, IStringLocalizer identityLocalizer, IStringLocalizer identityServerLocalizer, IStringLocalizer wechatLocalizer, AbpWeChatOfficialOptionsFactory weChatOfficialOptionsFactory) - : base(eventService, weChatOpenIdFinder, userManager, userRepository, identityLocalizer, identityServerLocalizer) + : base(eventService, weChatOpenIdFinder, userManager, userRepository, identitySecurityLogManager, identityLocalizer, identityServerLocalizer) { WeChatLocalizer = wechatLocalizer; WeChatOfficialOptionsFactory = weChatOfficialOptionsFactory; diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/WeChatGrantValidator.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/WeChatGrantValidator.cs index a8883d4fd..1215e081f 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/WeChatGrantValidator.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.WeChat/LINGYUN/Abp/IdentityServer/WeChat/WeChatGrantValidator.cs @@ -1,5 +1,4 @@ - -using IdentityModel; +using IdentityModel; using IdentityServer4.Events; using IdentityServer4.Models; using IdentityServer4.Services; @@ -19,11 +18,13 @@ using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; using Volo.Abp.Identity; +using Volo.Abp.IdentityServer; using Volo.Abp.IdentityServer.Localization; using Volo.Abp.MultiTenancy; using Volo.Abp.Security.Claims; using Volo.Abp.Settings; using Volo.Abp.Uow; + using IdentityResource = Volo.Abp.Identity.Localization.IdentityResource; using IdentityUser = Volo.Abp.Identity.IdentityUser; @@ -41,6 +42,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat protected IEventService EventService { get; } protected IWeChatOpenIdFinder WeChatOpenIdFinder { get; } protected IIdentityUserRepository UserRepository { get; } + protected IdentitySecurityLogManager IdentitySecurityLogManager { get; } protected UserManager UserManager { get; } protected IStringLocalizer IdentityLocalizer { get; } protected IStringLocalizer IdentityServerLocalizer { get; } @@ -50,12 +52,14 @@ namespace LINGYUN.Abp.IdentityServer.WeChat IWeChatOpenIdFinder weChatOpenIdFinder, UserManager userManager, IIdentityUserRepository userRepository, + IdentitySecurityLogManager identitySecurityLogManager, IStringLocalizer identityLocalizer, IStringLocalizer identityServerLocalizer) { EventService = eventService; UserManager = userManager; UserRepository = userRepository; + IdentitySecurityLogManager = identitySecurityLogManager; WeChatOpenIdFinder = weChatOpenIdFinder; IdentityLocalizer = identityLocalizer; IdentityServerLocalizer = identityServerLocalizer; @@ -81,7 +85,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityServerLocalizer["InvalidGrant:GrantTypeInvalid"]); return; } - // TODO: 统一命名规范, 微信认证传递的 code 改为 WeChatOpenIdConsts.WeCahtCodeKey + var wechatCode = raw.Get(AbpWeChatGlobalConsts.TokenName); if (wechatCode.IsNullOrWhiteSpace() || wechatCode.IsNullOrWhiteSpace()) { @@ -94,6 +98,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChat var currentUser = await UserManager.FindByLoginAsync(LoginProvider, wechatOpenId.OpenId); if (currentUser == null) { + // 检查是否允许自注册 var settingProvider = ServiceProvider.LazyGetRequiredService(); // TODO 检查启用用户注册是否有必要引用账户模块 if (!await settingProvider.IsTrueAsync("Abp.Account.IsSelfRegistrationEnabled") || @@ -117,37 +122,108 @@ namespace LINGYUN.Abp.IdentityServer.WeChat AbpWeChatGlobalConsts.DisplayName))).CheckErrors(); } + // 检查是否已锁定 if (await UserManager.IsLockedOutAsync(currentUser)) { Logger.LogInformation("Authentication failed for username: {username}, reason: locked out", currentUser.UserName); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, IdentityLocalizer["Volo.Abp.Identity:UserLockedOut"]); - return; - } - var sub = await UserManager.GetUserIdAsync(currentUser); + await SaveSecurityLogAsync(context, currentUser, wechatOpenId, IdentityServerSecurityLogActionConsts.LoginLockedout); - var additionalClaims = new List(); - if (currentUser.TenantId.HasValue) - { - additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString())); - } - additionalClaims.Add(new Claim(AbpWeChatClaimTypes.OpenId, wechatOpenId.OpenId)); - if (!wechatOpenId.UnionId.IsNullOrWhiteSpace()) - { - additionalClaims.Add(new Claim(AbpWeChatClaimTypes.UnionId, wechatOpenId.UnionId)); + return; } await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, wechatOpenId.OpenId, null)); - context.Result = new GrantValidationResult(sub, AuthenticationMethod, additionalClaims.ToArray()); - // 登录之后需要更新安全令牌 (await UserManager.UpdateSecurityStampAsync(currentUser)).CheckErrors(); + + await SetSuccessResultAsync(context, currentUser, wechatOpenId); } protected virtual Task CheckFeatureAsync(ExtensionGrantValidationContext context) { return Task.FromResult(true); } + + protected virtual async Task SetSuccessResultAsync(ExtensionGrantValidationContext context, IdentityUser user, WeChatOpenId wechatOpenId) + { + var sub = await UserManager.GetUserIdAsync(user); + + Logger.LogInformation("Credentials validated for username: {username}", user.UserName); + + var additionalClaims = new List(); + + await AddCustomClaimsAsync(additionalClaims, user, wechatOpenId, context); + + context.Result = new GrantValidationResult( + sub, + AuthenticationMethod, + additionalClaims.ToArray() + ); + + await SaveSecurityLogAsync( + context, + user, + wechatOpenId, + IdentityServerSecurityLogActionConsts.LoginSucceeded); + } + + protected virtual async Task SaveSecurityLogAsync( + ExtensionGrantValidationContext context, + IdentityUser user, + WeChatOpenId wechatOpenId, + string action) + { + var logContext = new IdentitySecurityLogContext + { + Identity = IdentityServerSecurityLogIdentityConsts.IdentityServer, + Action = action, + UserName = user.UserName, + ClientId = await FindClientIdAsync(context) + }; + logContext.WithProperty("GrantType", GrantType); + logContext.WithProperty("Provider", LoginProvider); + logContext.WithProperty("Method", AuthenticationMethod); + + await IdentitySecurityLogManager.SaveAsync(logContext); + } + + protected virtual Task FindClientIdAsync(ExtensionGrantValidationContext context) + { + return Task.FromResult(context.Request?.Client?.ClientId); + } + + protected virtual Task AddCustomClaimsAsync( + List customClaims, + IdentityUser user, + WeChatOpenId wechatOpenId, + ExtensionGrantValidationContext context) + { + if (user.TenantId.HasValue) + { + customClaims.Add( + new Claim( + AbpClaimTypes.TenantId, + user.TenantId?.ToString() + ) + ); + } + + customClaims.Add( + new Claim( + AbpWeChatClaimTypes.OpenId, + wechatOpenId.OpenId)); + + if (!wechatOpenId.UnionId.IsNullOrWhiteSpace()) + { + customClaims.Add( + new Claim( + AbpWeChatClaimTypes.UnionId, + wechatOpenId.UnionId)); + } + + return Task.CompletedTask; + } } }