zoukankan      html  css  js  c++  java
  • 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(1, 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 == "13488888888" && smsCode == "123456")
                {
                    List<Claim> claimList = new List<Claim>();
                    claimList.Add(new Claim("userID", "1"));
    
                    context.Result = new GrantValidationResult(
                     subject: phoneNumber,
                     authenticationMethod: ExtensionGrantTypes.SMSGrantType,
                     claims: claimList);
                }
                else
                { 
                    context.Result = new GrantValidationResult(
                        TokenRequestErrors.InvalidGrant,
                        "短信码错误!"
                        );
                }
                return Task.FromResult(0);
    
            }
        }

    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("123456".Sha256()) },
                        AccessTokenLifetime = 60*60,//单位s
                        AllowedGrantTypes = new[] {ExtensionGrantTypes.SMSGrantType}, //一个 Client 可以配置多个 GrantType
                        SlidingRefreshTokenLifetime =  2592000,
                        AllowOfflineAccess = true,
                        AllowedScopes = new List<string>
                        {
                            "FrameworkAPI",//对应webapi里面的scope配置
                            StandardScopes.OfflineAccess,
                            StandardScopes.OpenId,
                            StandardScopes.Profile
                        }
                    }

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

  • 相关阅读:
    Codeforces G. Ciel the Commander
    点分治模板
    Codeforces I. Vessels(跳转标记)
    Codeforces C. Maximum Value(枚举二分)
    Codeforces D. Little Elephant and Interval(思维找规律数位dp)
    [USACO15DEC]最大流Max Flow(树上差分)
    Codeforces E. Alyona and a tree(二分树上差分)
    一致性Hash算法
    零拷贝
    Maven 指定范围依赖
  • 原文地址:https://www.cnblogs.com/fengchao1000/p/11454704.html
Copyright © 2011-2022 走看看