IdentityServer4源碼頒發token分析及性能優化

IdentityServer4源碼地址git

IdentityModel源碼地址github

  1. 如下的流程用ResourceOwnerPassword類型獲取token做爲介紹
  2. 分兩種獲取形式說明
    1. token請求地址爲默認TokenEndPoint的地址:"http://demo/connect/token"獲取token
    2. 用IdentityModel的TokenClient請求獲取token【 性能優化點也在這個地方】

 


 

1.默認TokenEndPoint形式 性能優化

 

 

 


 

2.TokenClient形式async

當請求的Token的地址沒有配置默認形式的時候,那就須要利用IdentityModel下的Client來進行請求 舉個例子ide

首先咱們須要去獲取當前系統的token終結點(tokenEndPoint),而後獲取到TokenClient,而後調用RequestResourceOwnerPasswordAsync進行Token頒發性能

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

{ ui

    res = await client.GetAsync(); spa

} code

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
相關文章
相關標籤/搜索