IdentityServer4源码颁发token分析及性能优化
- 以下的流程用ResourceOwnerPassword类型获取token作为介绍
- 分两种获取形式说明
- token请求地址为默认TokenEndPoint的地址:"http://demo/connect/token"获取token
- 用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.cs和TokenClient.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"));
}
}
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);
}
}
}
IdentityServer4源码颁发token分析及性能优化的更多相关文章
- IdentityServer4源码解析_1_项目结构
目录 IdentityServer4源码解析_1_项目结构 IdentityServer4源码解析_2_元数据接口 IdentityServer4源码解析_3_认证接口 IdentityServer4 ...
- identityserver4源码解析_2_元数据接口
目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4 ...
- IdentityServer4源码解析_4_令牌发放接口
目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4 ...
- HTTP请求库——axios源码阅读与分析
概述 在前端开发过程中,我们经常会遇到需要发送异步请求的情况.而使用一个功能齐全,接口完善的HTTP请求库,能够在很大程度上减少我们的开发成本,提高我们的开发效率. axios是一个在近些年来非常火的 ...
- 如何实现一个HTTP请求库——axios源码阅读与分析 JavaScript
概述 在前端开发过程中,我们经常会遇到需要发送异步请求的情况.而使用一个功能齐全,接口完善的HTTP请求库,能够在很大程度上减少我们的开发成本,提高我们的开发效率. axios是一个在近些年来非常火的 ...
- identityserver4源码解析_3_认证接口
目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4 ...
- IdentityServer4源码解析_5_查询用户信息接口
协议简析 UserInfo接口是OAuth2.0中规定的需要认证访问的接口,可以返回认证用户的声明信息.请求UserInfo接口需要使用通行令牌.响应报文通常是json数据格式,包含了一组claim键 ...
- 从源码的角度分析ViewGruop的事件分发
从源码的角度分析ViewGruop的事件分发. 首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View ...
- 安卓图表引擎AChartEngine(二) - 示例源码概述和分析
首先看一下示例中类之间的关系: 1. ChartDemo这个类是整个应用程序的入口,运行之后的效果显示一个list. 2. IDemoChart接口,这个接口定义了三个方法, getName()返回值 ...
随机推荐
- Heartbeat详解
转自:http://blog.sina.com.cn/s/blog_7b6fc4c901012om0.html 配置主节点的Heartbeat Heartbeat的主要配置文件有ha.cf.hares ...
- EF + mysql 异常:Unable to load the specified metadata resource
数据库连接字符串报错, <add name="xxxx" providerName="MySql.Data.MySqlClient" connection ...
- 《Java核心技术卷1》拾遗
之前对Java的基础知识有过学习,现在开始学习<Java核心技术卷1>,将一些新学的知识点,做简要记录,以备后续回顾: 1.double (1)所有的“非数值”都认为是不相同的 if(x= ...
- (摘录)Java 详解 JVM 工作原理和流程
作为一名Java使用者,掌握JVM的体系结构也是必须的. 说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Java编程语言.Java类文件格式.Java ...
- Minieye杯第十五届华中科技大学程序设计邀请赛现场同步赛 I Matrix Again
Minieye杯第十五届华中科技大学程序设计邀请赛现场同步赛 I Matrix Again https://ac.nowcoder.com/acm/contest/700/I 时间限制:C/C++ 1 ...
- go的基本数据类型
一,数据类型的介绍 在go语言中,数据类型是用于声明函数和变量的:数据类型是为了把数据分成所需内存不同大小的数据,除了在需要使用大数据的时候才会申请大内存,这样就会充分的使用内存 Go 语言按类别有以 ...
- LOJ-10104(割点+dfs)
题目链接:传送门 思路: 求割点的同时求割点删除后所剩的不连通的点的对数,在遍历完成后回溯统计点的个数,具体操作见代码: 注意:结果是long long 类型. #include<iostrea ...
- Win7 VS2017编译PBR渲染引擎google filament
按照官方说明 https://github.com/google/filament 前置工具包 Windows 10 SDKVisual Studio 2017Clang 6Python 3.7Git ...
- SSH通过密钥登陆
A服务器上操作 ssh-keygen -t rsa/dsa 后面所带参数rsa/dsa为加密方式,默认为dsa [root@localhost ~]# ssh-keygen Generating pu ...
- ES6学习:两个面试题目--关于模板字符串
号称看完就能“让开发飞起来”,不过文中的两个面试题目的知识点并没包括在文中. https://www.jianshu.com/p/287e0bb867ae 文中并没有完整的知识点去完成上面的两道题,这 ...