扩展.Net Core Identity Server 授权方式,实现 手机号+ 验证码 登录
作者:互联网
背景
国内来讲,注册/登录流程都是尽可能的简单,注册流程复杂,容易流失客户。手机号 + 短信验证码的方式非常普遍;但是框架默认并没有类似的功能,需要我们自己进行扩展。
思路
- 验证登录手机号为注册用户,且验证码正确;验证通过后,去 Identity Server 获取Token,然后返回客户端。
- 扩展 Identity 的授权方式,类似于 Authorization code;关于gtant type 可以参考 Grant Types — IdentityServer4 1.0.0 documentation (identityserver4test.readthedocs.io)
不过扩由于Identity Server 要收费,以及Abp 6.0 要集成 OpenIdDict;扩展 Grant Type 的方式,可以适用于当前,后续根据需要进行调整。
定义 GrantTypes
1 public class IdentityGrantTypes 2 { 3 public const string PhoneCode = "phone_code"; 4 } 5View Code
实现 IExtensionGrantValidator
主要实现对手机号以及短信验证码的校验
1 public class PhoneCodeGrantValidator : IExtensionGrantValidator, ITransientDependency 2 { 3 private readonly IOptions<IdentityOptions> _identityOptions; 4 private readonly IAccountRepository _accountRepository; 5 private readonly IdentityUserManager _identityUserManager; 6 private readonly AccountTokenManager _accountTokenManager; 7 8 public string GrantType => IdentityGrantTypes.PhoneCode; 9 10 public PhoneCodeGrantValidator( 11 IOptions<IdentityOptions> identityOptions, 12 IAccountRepository accountRepository, 13 IdentityUserManager identityUserManager, 14 AccountTokenManager accountTokenManager) 15 { 16 _identityOptions = identityOptions; 17 _accountRepository = accountRepository; 18 _identityUserManager = identityUserManager; 19 _accountTokenManager = accountTokenManager; 20 } 21 22 public async Task ValidateAsync(ExtensionGrantValidationContext context) 23 { 24 await _identityOptions.SetAsync(); 25 26 var phoneNumber = context.Request.Raw.Get("phoneNumber"); 27 var code = context.Request.Raw.Get("code"); 28 29 var validateParamsResult = ValidateRequestParams(phoneNumber, code); 30 if (!validateParamsResult.IsNullOrWhiteSpace()) 31 { 32 SetContextError(validateParamsResult, context); 33 return; 34 } 35 36 var identityUser = await _accountRepository.FindByConfirmedPhoneAsync(phoneNumber); 37 if (identityUser == null) 38 { 39 SetContextError("无效的手机号", context); 40 return; 41 } 42 43 if (await _identityUserManager.IsLockedOutAsync(identityUser)) 44 { 45 SetContextError("账户已锁定", context); 46 return; 47 } 48 49 var validateCodeResult = await ValidateCodeLoginAsync(phoneNumber, code); 50 if (!validateCodeResult.IsNullOrWhiteSpace()) 51 { 52 await _identityUserManager.AccessFailedAsync(identityUser); 53 SetContextError(validateCodeResult, context); 54 return; 55 } 56 57 var claims = new List<Claim> 58 { 59 new("phoneNumber", phoneNumber) 60 }; 61 62 if (identityUser.TenantId.HasValue) 63 { 64 claims.Add(new Claim(AbpClaimTypes.TenantId, identityUser.TenantId?.ToString())); 65 } 66 67 claims.AddRange(identityUser.Claims.Select( 68 item => new Claim(item.ClaimType, item.ClaimValue))); 69 70 context.Result = new GrantValidationResult(identityUser.Id.ToString(), GrantType, claims); 71 } 72 73 public async Task<string> ValidateCodeLoginAsync(string phoneNumber, string code) 74 { 75 var isValidCode = await _accountTokenManager.VerifySignInCodeAsync(phoneNumber, code); 76 77 return !isValidCode ? "无效的手机号或验证码" : string.Empty; 78 } 79 80 private static string ValidateRequestParams( 81 string phoneNumber, string code) 82 { 83 if (string.IsNullOrWhiteSpace(phoneNumber)) 84 { 85 return "手机号不能为空"; 86 } 87 88 if (string.IsNullOrWhiteSpace(code)) 89 { 90 return "验证码不能为空"; 91 } 92 93 return string.Empty; 94 } 95 96 private static void SetContextError( 97 string errorMessage, ExtensionGrantValidationContext context) 98 { 99 context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant) 100 { 101 ErrorDescription = errorMessage 102 }; 103 } 104 }View Code
注册扩展服务
1 public override void PreConfigureServices(ServiceConfigurationContext context) 2 { 3 PreConfigure<IIdentityServerBuilder>(builder => 4 { 5 builder.AddExtensionGrantValidator<PhoneCodeGrantValidator>(); 6 }); 7 }
简单验证
至此,扩展方式的核心工作已经准备完成,可以通过 postman 进行简单的实验。
非扩展授权方式
此方式也比较简单,校验手机号以及验证码的主体逻辑一致,只需要验证用户之后,通过 httpClient 去 IdentityServer 获取token,然后返回客户端即可。
其他:为了更好的安全,在登录失败后需要显式的标记登录失败,配合 Identity 的一些策略,可以对一段时间内登录失败次数过多的账户,进行锁定,防止用户信息泄露。
结尾
近期已经从公司离职了。近期也思考了很多,大城市与二线城市在做事风格上确实差别比较大;也有很多令人唏嘘的事情,改天总结一下。
标签:Core,code,return,string,Server,phoneNumber,context,Net,public 来源: https://www.cnblogs.com/qiu-gu/p/16194195.html