DotNetOpenAuth Part 1 : Authorization 验证服务实现及关键源码解析
DotNetOpenAuth 是 .Net 环境下OAuth 开源实现框架。基于此,可以方便的实现 OAuth 验证(Authorization)服务、资源(Resource)服务。针对 DotNetOpenAuth,近期打算整理出三篇随笔:
DotNetOpenAuth Part 1 : OAuth2 Authorization 验证服务实现及关键源码解析
DotNetOpenAuth Part 2 : OAuth2 Resource 资源服务实现及关键源码解析
DotNetOpenAuth Part 3 : OAuth2 Client 访问实现几关键源码解析
本篇是这一系列的 Part 1。
OAuth Authorization 服务负责为用户下发 Access Token,而后用户用这一 Token 去请求资源和逻辑访问。Client 端发送来附带 ClientId 和 ClientSecret 的 request,Authorization 端验证请求的合法性,生成 Access Token 并下发,这就是OAuth 验证服务的主要职责。

【实现层面】
基于 DotNetOpenAuth 开发 Authorization 服务的主要工作是实现 IAuthorizationServerHost 接口,而其中关键要实现的方法有两个,它们分别是 GetClient 和 CreateAccessToken。
IClientDescription GetClient(string clientIdentifier);
由 Client 端发送来的标示 clientIdentifier 获取该 Client 在验证服务端的详细信息,以备做 ClientSecret 比对验证。这里 ClientDescription 的来源可以是验证服务端DB,也可以是其他可提供该数据的外部服务。
AccessTokenResult CreateAccessToken(IAccessTokenRequest accessTokenRequestMessage);
基于策略,生成 AccessToken,并返回给请求验证的 Client。
方法实现示意
GetClient,
public IClientDescription GetClient(string clientIdentifier)
{
if (string.Equals(clientIdentifier, "iSun", StringComparison.CurrentCulture))
{
var client = new Client() // Just initiate a Client instance, and in production it comes from DB or other service.
{
Name = "iSun",
ClientSecret = "",
ClientTypeValue =
}; return client;
} throw new ArgumentOutOfRangeException("clientIdentifier");
}
CreateAccessToken,
public AccessTokenResult CreateAccessToken(IAccessTokenRequest accessTokenRequestMessage)
{
var accessToken = new AuthorizationServerAccessToken(); accessToken.Lifetime = TimeSpan.FromMinutes();
accessToken.ResourceServerEncryptionKey = ... ...
accessToken.AccessTokenSigningKey = ... ... var result = new AccessTokenResult(accessToken);
return result;
}
实现了 IAuthorizationServerHost 接口下的两个关键方法,下面要做的仅仅是使用该 AuthorizationServerHost 实例初始化 AuthorizationServer 类,并调用其 HandleTokenRequestAsync 方法。
private readonly AuthorizationServer authorizationServer = new AuthorizationServer(new iSunAuthorizationServerHost(AuthService.Configuration)); public async Task<ActionResult> Token()
{
var response = await authorizationServer.HandleTokenRequestAsync(Request);
return response.AsActionResult();
}
【原理层面】
实现层面的介绍就是这些,是不是很简单?但仅知道这些显然不够,你始终还是不明 ... 但觉厉。DotNetOpenAuth Authorization 框架如何做到仅这两个方法就实现了验证服务呢?好在 DotNetOpenAuth 是开源项目,我们研究一下源码就会豁然开朗。先上一张 Authorization 内部调用的示意图(点击打开大图)。

如图所示,调用始自 AuthorizationServer.HandleTokenRequestAsync,后依次经步骤1 - 9,终于 AuthorizationServerHost.CreateAccessToken 调用。其中步骤7、8、9是整个 Token 下发过程中的关键方法调用。Step 7 GetClient 获取 request 端的详细信息,之后Step 8 IsValidClientSecret 验证 ClientSecret 合法性,若验证通过则Step 9 CreateAccessToken 并下发予请求的 Client 端。逻辑示意图如下(点击打开大图)。

关键步骤7、8、9源码片段如下:
调用 GetClient,并进行 ClientSecret Validation(DotNetOpenAuth.OAuth2.ChannelElements.ClientAuthenticationModule 中 TryAuthenticateClientBySecret 方法)。
protected static ClientAuthenticationResult TryAuthenticateClientBySecret(IAuthorizationServerHost authorizationServerHost,
string clientIdentifier, string clientSecret) {
Requires.NotNull(authorizationServerHost, "authorizationServerHost"); if (!string.IsNullOrEmpty(clientIdentifier)) {
var client = authorizationServerHost.GetClient(clientIdentifier); // Step 7: GetClient returns IClientDescription
if (client != null) {
if (!string.IsNullOrEmpty(clientSecret)) {
if (client.IsValidClientSecret(clientSecret)) { // Step 8: Validate ClientSecret
return ClientAuthenticationResult.ClientAuthenticated;
} else { // invalid client secret
return ClientAuthenticationResult.ClientAuthenticationRejected;
}
}
}
}
}
ClientDescription.IsValidClientSecret 方法(DotNetOpenAuth.OAuth2.ClientDescription 中 IsValidClientSecret 方法)。
 public virtual bool IsValidClientSecret(string secret) {
     Requires.NotNullOrEmpty(secret, "secret");
     return MessagingUtilities.EqualsConstantTime(secret, this.secret);
 }
调用 CreateAccessToken 代码片段,若 Client 验证未通过,则返回 InvalidRequest(line 23)(DotNetOpenAuth.OAuth2.AuthorizationServer 中方法 HandleTokenRequestAsync)。
AccessTokenRequestBase requestMessage = await this.Channel.TryReadFromRequestAsync<AccessTokenRequestBase>(request, cancellationToken);
if (requestMessage != null) {
// Step 9: Call AuthorizationServerHost.CreateAccessToken to generate Token
var accessTokenResult = this.AuthorizationServerServices.CreateAccessToken(requestMessage);
ErrorUtilities.VerifyHost(accessTokenResult != null, "IAuthorizationServerHost.CreateAccessToken must not return null."); IAccessTokenRequestInternal accessRequestInternal = requestMessage;
accessRequestInternal.AccessTokenResult = accessTokenResult; var successResponseMessage = this.PrepareAccessTokenResponse(requestMessage, accessTokenResult.AllowRefreshToken);
successResponseMessage.Lifetime = accessTokenResult.AccessToken.Lifetime;
......
responseMessage = successResponseMessage;
} else {
// Validation failed, return error with InvalidRequest
responseMessage = new AccessTokenFailedResponse() { Error = Protocol.AccessTokenRequestErrorCodes.InvalidRequest };
}
【小结】
应用 DotNetOpenAuth 框架开发 OAuth 验证服务比较容易,但如果不了解其实现原理,开发过程中不免心虚,遇到问题也不能快速解决。所以,不仅知其然,知其所以然还是很重要的。(此篇所示代码多为示意用途,若想下载Demo,参考资料2处有详细代码,我在本篇就不贴出了。需要 DotNetOpenAuth 源码和 Sample 的,可前往官网 http://www.dotnetopenauth.net/)
参考资料:
1、[OAuth]基于DotNetOpenAuth实现Client Credentials Grant http://www.cnblogs.com/dudu/p/oauth-dotnetopenauth-client-credentials-grant.html
2、DotNetOpenAuth实践之搭建验证服务器 http://www.cnblogs.com/idefav2010/p/DotNetOpenAuth.html
3、http://www.dotnetopenauth.net/
DotNetOpenAuth Part 1 : Authorization 验证服务实现及关键源码解析的更多相关文章
- Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战
		
Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战 Java生鲜电商平台- 什么是秒杀 通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动 比如说京东秒杀,就是一种定时定量秒杀,在规定 ...
 - netty服务端启动--ServerBootstrap源码解析
		
netty服务端启动--ServerBootstrap源码解析 前面的第一篇文章中,我以spark中的netty客户端的创建为切入点,分析了netty的客户端引导类Bootstrap的参数设置以及启动 ...
 - 微服务配置中心 Apollo 源码解析——Admin 发送发布消息
		
内容参考:https://www.toutiao.com/a6643383570985386509/ 摘要: 原创出处http://www.iocoder.cn/Apollo/admin-server ...
 - Netty5服务端源码解析
		
Netty5源码解析 今天让我来总结下netty5的服务端代码. 服务端(ServerBootstrap) 示例代码如下: import io.netty.bootstrap.ServerBootst ...
 - Spring-cloud & Netflix 源码解析:Eureka 服务注册发现接口 ****
		
http://www.idouba.net/spring-cloud-source-eureka-client-api/?utm_source=tuicool&utm_medium=refer ...
 - Netty 4源码解析:服务端启动
		
Netty 4源码解析:服务端启动 1.基础知识 1.1 Netty 4示例 因为Netty 5还处于测试版,所以选择了目前比较稳定的Netty 4作为学习对象.而且5.0的变化也不像4.0这么大,好 ...
 - 原创:用python把链接指向的网页直接生成图片的http服务及网站(含源码及思想)
		
原创:用python把链接指向的网页直接生成图片的http服务及网站(含源码及思想) 总体思想: 希望让调用方通过 http调用传入一个需要生成图片的网页链接生成一个网页的图片并返回图片链接 ...
 - Netty源码解析---服务端启动
		
Netty源码解析---服务端启动 一个简单的服务端代码: public class SimpleServer { public static void main(String[] args) { N ...
 - Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析
		
Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析 说明:Java生鲜电商平台中,由于服务进行了拆分,很多的业务服务导致了请求的网络延迟与性能消耗,对应的这些问题,我们 ...
 
随机推荐
- DDL-常见的约束
			
一.常见的约束NOT NULL:非空,该字段的值必填UNIQUE:唯一,该字段的值不可重复DEFAULT:默认,该字段的值不用手动插入有默认值CHECK:检查,mysql不支持PRIMARY KEY: ...
 - 用js计算自己从出生到现在生活了多长时间(x天零x小时零x分钟零x秒) 初学者,大家多多包涵,有不足的地方请多包涵。
			
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
 - iOS audio不支持循环播放
			
解决办法:监听播放完成事件(注意点,audio标签不能设置循环播放,去除标签 loop="loop"或者 loop="false",不然不走播放完成事件) $( ...
 - 1015 德才论(sort、结构体vector)
			
题目: 宋代史学家司马光在<资治通鉴>中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人.凡取人之术,苟不得圣人,君子而与之,与其得小人,不 ...
 - shell的奇淫巧技--自动化脚本(sed命令)
			
使用场景:前段时间交易所项目需要在服务器上用到 根据websocket推送价格数据,在交易所内进行下单撤单处理,但是由于有多个交易对,在服务器上部署时候,略显繁琐.(撮合引擎同样有此问题,可以一并解决 ...
 - 前端用node+mysql实现简单服务端
			
node express + mysql实现简单服务端前端新人想写服务端不想学PHP等后端语言怎么办,那就用js写后台吧!这也是我这个前端新人的学习成果分享,如有那些地方不对,请给我指出. 1.准备工 ...
 - 【原创】Dynamics CRM 2015/2016,以PDF的形式打开SSRS报表。
			
基本步骤: 使用SSRS建立报表,以下的例子是以记录的GUID作为报表的参数 获取ReportSession 和 ControlId来调用报表 以PDF的形式预览报表 一.根据报表的名称获取报表的GU ...
 - micro:bit 软件生态系统介绍
			
microbit 软件分成在microbit (Target Computer 如下图右边)上执行的及主计算机(Host Computer 如下图左边)上两类 : 一般程序写好后透过USB 转到mic ...
 - 移植ARM linux下远程连接工具dropbear
			
移植ARM linux下远程连接工具dropbear 原文地址:http://www.cnblogs.com/NickQ/p/9010529.html 移植zlib 下载地址:https://gith ...
 - 数构与算法 | 什么是大 O 表示算法时间复杂度
			
正文: 开篇我们先思考这么一个问题:一台老式的 CPU 的计算机运行 O(n) 的程序,和一台速度提高的新式 CPU 的计算机运 O(n2) 的程序.谁的程运行效率高呢? 答案是前者优于后者.为什么呢 ...