新文章 网摘 文章 随笔 日记

IdentityServer4 自定义授权模式

IdentityServer4除了提供常规的几种授权模式外(AuthorizationCode、ClientCredentials、Password、RefreshToken、DeviceCode),还提供了可以拓展的授权模式,下面就根据源码简单说下IdentityServer4是如何实现自定义授权模式的。

一、查看IdentityServer4自定义授权模式源码

当用户请求 connect/token 地址时,会执行TokenRequestValidator类的ValidateRequestAsync方法,在ValidateRequestAsync方法中根据GrantTypes类型调用不同的Validate方法,如下:

  1. public async Task<TokenRequestValidationResult> ValidateRequestAsync(NameValueCollection parameters, ClientSecretValidationResult clientValidationResult)
  2. {
  3. //去掉了部分代码。。。
  4.  
  5. _validatedRequest.GrantType = grantType;
  6.  
  7. switch (grantType)
  8. {
  9. case OidcConstants.GrantTypes.AuthorizationCode:
  10. return await RunValidationAsync(ValidateAuthorizationCodeRequestAsync, parameters);
  11. case OidcConstants.GrantTypes.ClientCredentials:
  12. return await RunValidationAsync(ValidateClientCredentialsRequestAsync, parameters);
  13. case OidcConstants.GrantTypes.Password:
  14. return await RunValidationAsync(ValidateResourceOwnerCredentialRequestAsync, parameters);
  15. case OidcConstants.GrantTypes.RefreshToken:
  16. return await RunValidationAsync(ValidateRefreshTokenRequestAsync, parameters);
  17. case OidcConstants.GrantTypes.DeviceCode:
  18. return await RunValidationAsync(ValidateDeviceCodeRequestAsync, parameters);
  19. default:
  20. return await RunValidationAsync(ValidateExtensionGrantRequestAsync, parameters);
  21. }
  22. }

自定义的授权模式会进入 ValidateExtensionGrantRequestAsync 方法 ,方法中会做一些简单的验证,然后调用 _extensionGrantValidator.ValidateAsync 方法,_extensionGrantValidator.ValidateAsync方法实现如下:

  1. public class ExtensionGrantValidator
  2. {
  3. private readonly ILogger _logger;
  4. private readonly IEnumerable<IExtensionGrantValidator> _validators;//可以注入多个自定义授权类,用集合保存
  5.  
  6. /// <summary>
  7. /// Initializes a new instance of the <see cref="ExtensionGrantValidator"/> class.
  8. /// </summary>
  9. /// <param name="validators">The validators.</param>
  10. /// <param name="logger">The logger.</param>
  11. public ExtensionGrantValidator(IEnumerable<IExtensionGrantValidator> validators, ILogger<ExtensionGrantValidator> logger)
  12. {
  13. if (validators == null)
  14. {
  15. _validators = Enumerable.Empty<IExtensionGrantValidator>();
  16. }
  17. else
  18. {
  19. //把注入的自定义授权类放入集合中
  20. _validators = validators;
  21. }
  22.  
  23. _logger = logger;
  24. }
  25.  
  26. /// <summary>
  27. /// 得到所有可用的自定义授权类型
  28. /// </summary>
  29. /// <returns></returns>
  30. public IEnumerable<string> GetAvailableGrantTypes()
  31. {
  32. return _validators.Select(v => v.GrantType);
  33. }
  34.  
  35. /// <summary>
  36. /// Validates the request.
  37. /// </summary>
  38. /// <param name="request">The request.</param>
  39. /// <returns></returns>
  40. public async Task<GrantValidationResult> ValidateAsync(ValidatedTokenRequest request)
  41. {
  42. //根据用户请求的GrantType获取自定义授权类
  43. var validator = _validators.FirstOrDefault(v => v.GrantType.Equals(request.GrantType, StringComparison.Ordinal));
  44.  
  45. if (validator == null)
  46. {
  47. _logger.LogError("No validator found for grant type");
  48. return new GrantValidationResult(TokenRequestErrors.UnsupportedGrantType);
  49. }
  50.  
  51. try
  52. {
  53. _logger.LogTrace("Calling into custom grant validator: {type}", validator.GetType().FullName);
  54.  
  55. var context = new ExtensionGrantValidationContext
  56. {
  57. Request = request
  58. };
  59. //执行验证方法,这里执行的就是我们自定义授权的验证方法
  60. await validator.ValidateAsync(context);
  61. return context.Result;
  62. }
  63. catch (Exception e)
  64. {
  65. _logger.LogError(, e, "Grant validation error: {message}", e.Message);
  66. return new GrantValidationResult(TokenRequestErrors.InvalidGrant);
  67. }
  68. }
  69. }

二、实现自定义授权

比如我们想实现短信登录,就可以自定义一个授权类型 SMSGrantType

1、创建自定义授权类 SMSGrantValidator  ,实现IExtensionGrantValidator接口

  1. public class SMSGrantValidator : IExtensionGrantValidator
  2. {
  3. public string GrantType => ExtensionGrantTypes.SMSGrantType;
  4.  
  5. public Task ValidateAsync(ExtensionGrantValidationContext context)
  6. {
  7. var smsCode = context.Request.Raw.Get("smsCode");
  8. var phoneNumber = context.Request.Raw.Get("phoneNumber");
  9.  
  10. if (string.IsNullOrEmpty(smsCode) || string.IsNullOrEmpty(phoneNumber))
  11. {
  12. context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
  13. }
  14.  
  15. if (phoneNumber == "" && smsCode == "")
  16. {
  17. List<Claim> claimList = new List<Claim>();
  18. claimList.Add(new Claim("userID", ""));
  19.  
  20. context.Result = new GrantValidationResult(
  21. subject: phoneNumber,
  22. authenticationMethod: ExtensionGrantTypes.SMSGrantType,
  23. claims: claimList);
  24. }
  25. else
  26. {
  27. context.Result = new GrantValidationResult(
  28. TokenRequestErrors.InvalidGrant,
  29. "短信码错误!"
  30. );
  31. }
  32. return Task.FromResult();
  33.  
  34. }
  35. }

2、在Startup中注入SMSGrantValidator

  1. services.AddIdentityServer()
  2. //配置证书
  3. .AddDeveloperSigningCredential()
  4. //配置API资源
  5. .AddInMemoryApiResources(Config.GetApis())
  6. //配置身份资源
  7. .AddInMemoryIdentityResources(Config.GetIdentityResources())
  8. //预置Client
  9. .AddInMemoryClients(Config.GetClients())
  10. //自定义登录返回信息
  11. .AddProfileService<ProfileService>()
  12. //添加Password模式下用于自定义登录验证
  13. .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
  14. //添加自定义授权模式
  15. .AddExtensionGrantValidator<SMSGrantValidator>();

3、配置Client

  1. //自定义短信验证模式
  2. new Client
  3. {
  4. ClientId = "sms",
  5. ClientName = "sms",
  6. ClientSecrets = { new Secret("".Sha256()) },
  7. AccessTokenLifetime = *,//单位s
  8. AllowedGrantTypes = new[] {ExtensionGrantTypes.SMSGrantType}, //一个 Client 可以配置多个 GrantType
  9. SlidingRefreshTokenLifetime = ,
  10. AllowOfflineAccess = true,
  11. AllowedScopes = new List<string>
  12. {
  13. "FrameworkAPI",//对应webapi里面的scope配置
  14. StandardScopes.OfflineAccess,
  15. StandardScopes.OpenId,
  16. StandardScopes.Profile
  17. }
  18. }

用postman测试,返回token,测试成功

 

https://www.bbsmax.com/A/6pdDwRvK5w/

posted @ 2021-12-01 10:57  岭南春  阅读(344)  评论(0)    收藏  举报