IdentityServer4 自定义授权模式
IdentityServer4除了提供常规的几种授权模式外(AuthorizationCode、ClientCredentials、Password、RefreshToken、DeviceCode),还提供了可以拓展的授权模式,下面就根据源码简单说下IdentityServer4是如何实现自定义授权模式的。
一、查看IdentityServer4自定义授权模式源码
当用户请求 connect/token 地址时,会执行TokenRequestValidator类的ValidateRequestAsync方法,在ValidateRequestAsync方法中根据GrantTypes类型调用不同的Validate方法,如下:
- public async Task<TokenRequestValidationResult> ValidateRequestAsync(NameValueCollection parameters, ClientSecretValidationResult clientValidationResult)
- {
- //去掉了部分代码。。。
- _validatedRequest.GrantType = grantType;
- switch (grantType)
- {
- case OidcConstants.GrantTypes.AuthorizationCode:
- return await RunValidationAsync(ValidateAuthorizationCodeRequestAsync, parameters);
- case OidcConstants.GrantTypes.ClientCredentials:
- return await RunValidationAsync(ValidateClientCredentialsRequestAsync, parameters);
- case OidcConstants.GrantTypes.Password:
- return await RunValidationAsync(ValidateResourceOwnerCredentialRequestAsync, parameters);
- case OidcConstants.GrantTypes.RefreshToken:
- return await RunValidationAsync(ValidateRefreshTokenRequestAsync, parameters);
- case OidcConstants.GrantTypes.DeviceCode:
- return await RunValidationAsync(ValidateDeviceCodeRequestAsync, parameters);
- default:
- return await RunValidationAsync(ValidateExtensionGrantRequestAsync, parameters);
- }
- }
自定义的授权模式会进入 ValidateExtensionGrantRequestAsync 方法 ,方法中会做一些简单的验证,然后调用 _extensionGrantValidator.ValidateAsync 方法,_extensionGrantValidator.ValidateAsync方法实现如下:
- public class ExtensionGrantValidator
- {
- private readonly ILogger _logger;
- private readonly IEnumerable<IExtensionGrantValidator> _validators;//可以注入多个自定义授权类,用集合保存
- /// <summary>
- /// Initializes a new instance of the <see cref="ExtensionGrantValidator"/> class.
- /// </summary>
- /// <param name="validators">The validators.</param>
- /// <param name="logger">The logger.</param>
- public ExtensionGrantValidator(IEnumerable<IExtensionGrantValidator> validators, ILogger<ExtensionGrantValidator> logger)
- {
- if (validators == null)
- {
- _validators = Enumerable.Empty<IExtensionGrantValidator>();
- }
- else
- {
- //把注入的自定义授权类放入集合中
- _validators = validators;
- }
- _logger = logger;
- }
- /// <summary>
- /// 得到所有可用的自定义授权类型
- /// </summary>
- /// <returns></returns>
- public IEnumerable<string> GetAvailableGrantTypes()
- {
- return _validators.Select(v => v.GrantType);
- }
- /// <summary>
- /// Validates the request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns></returns>
- public async Task<GrantValidationResult> ValidateAsync(ValidatedTokenRequest request)
- {
- //根据用户请求的GrantType获取自定义授权类
- var validator = _validators.FirstOrDefault(v => v.GrantType.Equals(request.GrantType, StringComparison.Ordinal));
- if (validator == null)
- {
- _logger.LogError("No validator found for grant type");
- return new GrantValidationResult(TokenRequestErrors.UnsupportedGrantType);
- }
- try
- {
- _logger.LogTrace("Calling into custom grant validator: {type}", validator.GetType().FullName);
- var context = new ExtensionGrantValidationContext
- {
- Request = request
- };
- //执行验证方法,这里执行的就是我们自定义授权的验证方法
- await validator.ValidateAsync(context);
- return context.Result;
- }
- catch (Exception e)
- {
- _logger.LogError(, e, "Grant validation error: {message}", e.Message);
- return new GrantValidationResult(TokenRequestErrors.InvalidGrant);
- }
- }
- }
二、实现自定义授权
比如我们想实现短信登录,就可以自定义一个授权类型 SMSGrantType
1、创建自定义授权类 SMSGrantValidator ,实现IExtensionGrantValidator接口
- public class SMSGrantValidator : IExtensionGrantValidator
- {
- public string GrantType => ExtensionGrantTypes.SMSGrantType;
- public Task ValidateAsync(ExtensionGrantValidationContext context)
- {
- var smsCode = context.Request.Raw.Get("smsCode");
- var phoneNumber = context.Request.Raw.Get("phoneNumber");
- if (string.IsNullOrEmpty(smsCode) || string.IsNullOrEmpty(phoneNumber))
- {
- context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
- }
- if (phoneNumber == "" && smsCode == "")
- {
- List<Claim> claimList = new List<Claim>();
- claimList.Add(new Claim("userID", ""));
- context.Result = new GrantValidationResult(
- subject: phoneNumber,
- authenticationMethod: ExtensionGrantTypes.SMSGrantType,
- claims: claimList);
- }
- else
- {
- context.Result = new GrantValidationResult(
- TokenRequestErrors.InvalidGrant,
- "短信码错误!"
- );
- }
- return Task.FromResult();
- }
- }
2、在Startup中注入SMSGrantValidator
- services.AddIdentityServer()
- //配置证书
- .AddDeveloperSigningCredential()
- //配置API资源
- .AddInMemoryApiResources(Config.GetApis())
- //配置身份资源
- .AddInMemoryIdentityResources(Config.GetIdentityResources())
- //预置Client
- .AddInMemoryClients(Config.GetClients())
- //自定义登录返回信息
- .AddProfileService<ProfileService>()
- //添加Password模式下用于自定义登录验证
- .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
- //添加自定义授权模式
- .AddExtensionGrantValidator<SMSGrantValidator>();
3、配置Client
- //自定义短信验证模式
- new Client
- {
- ClientId = "sms",
- ClientName = "sms",
- ClientSecrets = { new Secret("".Sha256()) },
- AccessTokenLifetime = *,//单位s
- AllowedGrantTypes = new[] {ExtensionGrantTypes.SMSGrantType}, //一个 Client 可以配置多个 GrantType
- SlidingRefreshTokenLifetime = ,
- AllowOfflineAccess = true,
- AllowedScopes = new List<string>
- {
- "FrameworkAPI",//对应webapi里面的scope配置
- StandardScopes.OfflineAccess,
- StandardScopes.OpenId,
- StandardScopes.Profile
- }
- }
用postman测试,返回token,测试成功

浙公网安备 33010602011771号