程序员的资源宝库

网站首页 > gitee 正文

IdentityServer4源码颁发token分析及性能优化

sanyeah 2024-04-19 23:56:05 gitee 4 ℃ 0 评论

IdentityServer4源码地址

IdentityModel源码地址

  1. 以下的流程用ResourceOwnerPassword类型获取token作为介绍
  2. 分两种获取形式说明
    1. token请求地址为默认TokenEndPoint的地址:"http://demo/connect/token"获取token
    2. 用IdentityModel的TokenClient请求获取token【 性能优化点也在这个地方】

 


 

1.默认TokenEndPoint形式 

 

 

 


 

2.TokenClient形式

当请求的Token的地址没有配置默认形式的时候,那就需要利用IdentityModel下的Client来进行请求 举个例子

首先我们需要去获取当前系统的token终结点(tokenEndPoint),然后获取到TokenClient,然后调用RequestResourceOwnerPasswordAsync进行Token颁发

using (var client = new DiscoveryClient(IssuerUri) { Policy = { RequireHttps = false } })

{

    res = await client.GetAsync();

}

var tokenClient = new TokenClient(res.TokenEndpoint, clientId, clientSecret);

var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync(username, password);

 

然后我们来看看实际在干什么。我们去看这部分IdentiyModel的源码 (TokenClientExtensions.csTokenClient.cs

 

 

 

 

图1的方法就是我们调用时的方法,可以看到它构造了一下form表单元素就去调用RequestAsync方法。RequestAsync 是使用了HttpClient发起了请求。请求的地址是我们前面获取到的tokenEndPoint的地址,

其实就是进行了一次跳转,问题点就在于这里,绕了一个"圈圈",压测出来效果并不好,为什么不选择直接本地调用方法形式去执行呢? 只需要 仿照 重写一个TokenClient和TokenEndPoint(一直感觉这东西

既然是执handler为什么不叫TokenEndPointHandler) 去把执行方法重写掉,去掉HTTP请求方式,换成直接本地调用方式。这样就直接到类似说明S2步骤

    public class LocalTokenClient : TokenClient
    {
        private readonly ILocalTokenEndpointHandler _endpointHandler;
        public LocalTokenClient(string address, string clientId, string clientSecret, ILocalTokenEndpointHandler endpointHandler, HttpMessageHandler innerHttpMessageHandler = null, AuthenticationStyle style = AuthenticationStyle.BasicAuthentication) : base(address, clientId, clientSecret, innerHttpMessageHandler, style)
        {
            _endpointHandler = endpointHandler;
        }

        public override async Task<TokenResponse> RequestAsync(IDictionary<string, string> form, CancellationToken cancellationToken = default(CancellationToken))
        {
            form.Add("client_id", ClientId);
            form.Add("client_secret", ClientSecret);

            try
            {
                var endpointResult = await _endpointHandler.ProcessAsync(form);
                if(endpointResult is TokenResult)
                {
                    TokenResult response = (TokenResult)endpointResult;
                    if (response != null && response.Response != null)
                    {
                        Dictionary<string, object> result = new Dictionary<string, object>();
                        result.Add("id_token", response.Response.IdentityToken);
                        result.Add("access_token", response.Response.AccessToken);
                        result.Add("refresh_token", response.Response.RefreshToken);
                        result.Add("expires_in", response.Response.AccessTokenLifetime);
                        result.Add("token_type", OidcConstants.TokenResponse.BearerTokenType);

                        if (!response.Response.Custom.IsNullOrEmpty())
                        {
                            foreach (var item in response.Response.Custom)
                            {
                                result.Add(item.Key, item.Value);
                            }
                        }

                        return new TokenResponse(Newtonsoft.Json.JsonConvert.SerializeObject(result));
                    }
                }
                else
                {
                    TokenErrorResult response = (TokenErrorResult)endpointResult;
                    string error = response.Response.Error;
                    if(response.Response.ErrorDescription!=null)
                    {
                       error = response.Response.ErrorDescription;
                    }
                    return new TokenResponse(new Exception(error));
                }
            }
            catch (Exception ex)
            {
                return new TokenResponse(ex);
            }

            return new TokenResponse(new Exception("request token failed"));
        }
    }
View Code

 

    public interface ILocalTokenEndpointHandler
    {
        /// <summary>
        /// Processes the request.
        /// </summary>
        /// <param name="context">The HTTP context.</param>
        /// <returns></returns>
        Task<IEndpointResult> ProcessAsync(IDictionary<string, string> form);
    }

    public class LocalTokenEndpoint : ILocalTokenEndpointHandler
    {
        private readonly ICustomClientSecretValidator _clientValidator;
        private readonly ITokenRequestValidator _requestValidator;
        private readonly ITokenResponseGenerator _responseGenerator;
        private readonly IEventService _events;
        private readonly ILogger _logger;
        private readonly IClientStore _clients;

        /// <summary>
        /// Initializes a new instance of the <see cref="TokenEndpoint" /> class.
        /// </summary>
        /// <param name="clientValidator">The client validator.</param>
        /// <param name="requestValidator">The request validator.</param>
        /// <param name="responseGenerator">The response generator.</param>
        /// <param name="events">The events.</param>
        /// <param name="logger">The logger.</param>
        public LocalTokenEndpoint(
            ICustomClientSecretValidator clientValidator,
            ITokenRequestValidator requestValidator,
            ITokenResponseGenerator responseGenerator,
            IEventService events,
            ILogger<LocalTokenEndpoint> logger,
            IClientStore clients)
        {
            _clientValidator = clientValidator;
            _requestValidator = requestValidator;
            _responseGenerator = responseGenerator;
            _events = events;
            _logger = logger;
            _clients = clients;
        }

        /// <summary>
        /// Processes the request.
        /// </summary>
        /// <param name="context">The HTTP context.</param>
        /// <returns></returns>
        public async Task<IEndpointResult> ProcessAsync(IDictionary<string, string> form)
        {
            _logger.LogTrace("Processing token request.");

            return await ProcessTokenRequestAsync(form);
        }

        private Task RaiseSuccessEventAsync(string clientId, string authMethod)
        {
            return _events.RaiseAsync(new ClientAuthenticationSuccessEvent(clientId, authMethod));
        }

        private async Task<IEndpointResult> ProcessTokenRequestAsync(IDictionary<string, string> form)
        {
            _logger.LogDebug("Start token request.");
            // validate client
            var clientResult = await _clientValidator.ValidateAsync(form);
            if (clientResult.Client == null)
            {
                return Error(OidcConstants.TokenErrors.InvalidClient);
            }

            // validate request
            var form2 = form.AsNameValueCollection();
            _logger.LogTrace("Calling into token request validator: {type}", _requestValidator.GetType().FullName);
            var requestResult = await _requestValidator.ValidateRequestAsync(form2, clientResult);

            if (requestResult.IsError)
            {
                await _events.RaiseAsync(new TokenIssuedFailureEvent(requestResult));
                return Error(requestResult.Error, requestResult.ErrorDescription, requestResult.CustomResponse);
            }

            // create response
            _logger.LogTrace("Calling into token request response generator: {type}", _responseGenerator.GetType().FullName);
            var response = await _responseGenerator.ProcessAsync(requestResult);

            await _events.RaiseAsync(new TokenIssuedSuccessEvent(response, requestResult));
            LogTokens(response, requestResult);

            // return result
            _logger.LogDebug("Token request success.");
            return new TokenResult(response);
        }

        private TokenErrorResult Error(string error, string errorDescription = null, Dictionary<string, object> custom = null)
        {
            var response = new TokenErrorResponse
            {
                Error = error,
                ErrorDescription = errorDescription,
                Custom = custom
            };

            return new TokenErrorResult(response);
        }

        private void LogTokens(TokenResponse response, TokenRequestValidationResult requestResult)
        {
            var clientId = $"{requestResult.ValidatedRequest.Client.ClientId} ({requestResult.ValidatedRequest.Client?.ClientName ?? "no name set"})";
            var subjectId = requestResult.ValidatedRequest.Subject?.GetSubjectId() ?? "no subject";

            if (response.IdentityToken != null)
            {
                _logger.LogTrace("Identity token issued for {clientId} / {subjectId}: {token}", clientId, subjectId, response.IdentityToken);
            }
            if (response.RefreshToken != null)
            {
                _logger.LogTrace("Refresh token issued for {clientId} / {subjectId}: {token}", clientId, subjectId, response.RefreshToken);
            }
            if (response.AccessToken != null)
            {
                _logger.LogTrace("Access token issued for {clientId} / {subjectId}: {token}", clientId, subjectId, response.AccessToken);
            }
        }
    }
View Code

 

猜你喜欢

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表