[认证授权] 2.OAuth2授权(续) & JWT(JSON Web Token)
1 RFC6749还有哪些可以完善的?
1.1 撤销Token
在上篇[认证授权] 1.OAuth2授权中介绍到了OAuth2可以帮我们解决第三方Client访问受保护资源的问题,但是只提供了如何获得access_token,并未说明怎么来撤销一个access_token。关于这部分OAuth2单独定义了一个RFC7009 - OAuth 2.0 Token Revocation来解决撤销Token问题。
1.2 Token对Client的不透明问题
OAuth2提供的“access_token"是一个对Client不透明的字符串,尽管有"scope","expires_in"和"refresh_token"来辅助,但也是不完善的且分散的信息。还拿上一篇的小明来举例,“小明授权在线打印并且包邮的网站访问自己的QQ空间的相册”。双引号里面的这句话其中有4个重要的概念:
- 授权者小明:表示是小明授权,而不是隔壁老王。
- 被授权者在线打印并且包邮的网站:表示授权给指定的网站,而不是其他的比如1024.com之类的网站(你懂的。。。)。
- 小明自己的QQ空间:表示让被授权者访问自己的信息,而不是隔壁老王的信息,小明也没这权限来着,不然隔壁王婶夜不答应吧。。。
- 相册:表示你可以访问我的相册,而不是我的日志,我的其他信息。
那么如何得到获得上面提到的这些附加的信息呢?OAuth2又单独提供了一个RFC7662 -OAuth 2.0 Token Introspection来解决Token的描述信息不完整的问题。
这些信息不但对Client不透明,对于资源服务器来说也是不透明的,比如授权服务器和资源服务器是独立部署的,而OAuth2又要求资源服务器要对access token做校验,没有这些信息如何校验呢?除非在access token的db存储层面做共享,但是作为一个运行在互联网规模上的网络环境下的协议,这种假设是无法支撑互联网规模的环境的。
2 OAuth2 Token 撤销(RFC7009 - OAuth2 Token Revocation)
简单来说,这个协议规定了一个Authorization server提供一个怎样的API来供Client撤销access_token或者refresh_token。
比如Client发起一个如下的请求:
POST /revoke HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JWtoken=45ghiukldjahdnhzdauz&token_type_hint=refresh_token
其中各项含义如下:
- /revoke:是Authorization Server需要提供的API地址,Client使用Post方式请求这个地址。
- Content-Type: application/x-www-form-urlencoded:固定此格式。
- Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW:访问受保护资源的授权凭证。
- token:必选,可以是access_token或者refresh_token的内容。
- token_type_hint:可选,表示token的类型,值为”access_token“或者"refresh_token"。
如果撤销成功,则返回一个HTTP status code为200的响应就可以了。
3 OAuth2 Token 元数据(RFC7662 - OAuth2 Token Introspection)
简单的总结来说,这个规范是为OAuth2扩展了一个API接口(Introspection Endpoint),让第三方Client可以查询上面提到的那些信息(比如,access_token是否还有效,谁颁发的,颁发给谁的,scope又哪些等等的元数据信息)。
比如Client发起一个如下的请求:
POST /introspect HTTP/1.1
Host: server.example.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer 23410913-abewfq.123483token=2YotnFZFEjr1zCsicMWpAA&token_type_hint=access_token
看起来和上面的撤销Token的请求差不多,其中各项含义如下:
- /introspect:是Authorization Server需要提供的API地址,Client使用Post方式请求这个地址。
- Accept:application/json:表示Authorization Server需要返回一个JSON格式的数据。
- Content-Type: application/x-www-form-urlencoded:固定此格式。
- Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW:访问受保护资源的授权凭证。
- token:必选,可以是access_token或者refresh_token的内容。
- token_type_hint:可选,表示token的类型,值为”access_token“或者"refresh_token"。
如果请求成功,则会返回如下的信息:
{
"active": true,
"client_id": "l238j323ds-23ij4",
"token_type":"access_token",
"username": "jdoe",
"scope": "read write dolphin",
"sub": "Z5O3upPC88QrAjx00dis",
"aud": "https://protected.example.net/resource",
"iss": "https://server.example.com/",
"exp": 1419356238,
"iat": 1419350238,
"nbf": 1419350238,
"jti": "abcdefg"
"extension_field": "twenty-seven"
}
JSON各项属性含义如下(其中有些信息是在JSON Web Token中定义的,参考链接有详细的介绍):
- active:必须的。表示token是否还是有效的。
- client_id:可选的。表示token所属的Client。比如上面的在线打印并且包邮的网站。
- token_type:可选的。表示token的类型。对应传递的token_type_hint。
- user_name:可选的。表示token的授权者的名字。比如上面的小明。
- scope:可选的。和上篇5.1.1 Authorization Request中的可选参数scope对应,表示授权给Client访问的范围,比如是相册,而不是小明的日志以及其他受保护资源。
- sub:可选的。token所属的资源拥有者的唯一标识,JWT定义的。也就是小明的唯一标识符。
- aud:可选的。token颁发给谁的,JWT定义的。
- iss:可选的。token的颁发者,JWT定义的。
- exp:可选的。token的过期时间,JWT定义的。
- iat:可选的。iss颁发token的时间,JWT定义的。
- nbf:可选的。token不会在这个时间之前被使用,JWT定义的。
- jti:可选的。token的唯一标识,JWT定义的。
- extension_field:可以自己扩展相关其他属性。
其中大量的信息都是可选的信息,而且可以自己扩展需要的属性信息,从这些属性中就可以解决我们上面提到的access_token对于Client不透明的问题。
我们注意到其中有很多属于JWT定义的属性,那么这个JWT是什么东西?它解决了什么问题?
4 JSON Web Token (JWT)
简单总结来说,JWT是一个定义一种紧凑的,自包含的并且提供防篡改机制的传递数据的方式的标准协议。
我们先来看一个简单的示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Imxpbmlhbmh1aSJ9.hnOfZb95jFwQsYj3qlgFbUu1rKpfTE6AzgXZidEGGTk
就是这么一堆看起来像是乱码一样的字符串。JWT由3部分构成:header.payload.signature,每个部分由“.”来分割开来。
4.1 Header
header是一个有效的JSON,其中通常包含了两部分:token类型和签名算法。
{
"alg": "HS256",
"typ": "JWT"
}
对这个JSON采用base64编码后就是第1部分eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9。
4.2 Payload
这一部分代表真正想要传递的数据,包含一组Claims,其中JWT预定义了一些Claim(2. Token 元数据 这一节就用到一些JWT预定义的一些Cliam)后面会介绍。关于什么是Claim,可以参考文章末尾给的参考链接。
{
"sub": "1234567890",
"name": "linianhui"
}
对这个JSON采用base64编码后就是第2部分eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Imxpbmlhbmh1aSJ9。
4.3 Signature
这一部分是可选的,由于前面Header和Payload部分是明文的信息,所以这一部分的意义在于保障信息不被篡改用的,生成这部分的方式如下:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
token生成方使用header中指定的签名算法对“header.payload”部分进行签名,得到的第3部分hnOfZb95jFwQsYj3qlgFbUu1rKpfTE6AzgXZidEGGTk,然后组合成一个完整的JWT字符串 . 而token消费方在拿到token后, 使用同样的签名算法来生成签名,用来判断header和payload部分有没有被篡改过,因为签名的密钥是只有通信双方知道的,所以可以保证这部分信息不被第三方所篡改。
4.4 JWT的一些Claims
JWT规范中预先定义了一些Cliam,但并不是必选的,常用的有:
iss(Issuer签发者)
。sub(subject签发给的受众,在Issuer范围内是唯一的)
。aud(Audience接收方)
。exp(Expiration Time过期时间)
。iat(Issued At签发时间)等等。
更完整的一些Claim列表参见:https://www.iana.org/assignments/jwt/jwt.xhtml
如果上面这些仍无法满足自己的需要,则可以自定义一些来使用。
4.5 JWT 应用场景
由于其采用base64来进行编码,使得它可以安全的用在一些仅限ASCII的地方传递信息,比如URL的querystring中。
比如用户登陆后,可以把用户的一些属性信息(用户标识,是否是管理员,权限有哪些等等可以公开的信息)用JWT编码存储在cookie中,由于其自包含的性质,每次服务器读取到Cookie的时候就可以解析到当前用户对应的属性信息,而不必再次去查询数据库。如果Cookie中每次都发送浪费带宽,也可以用 Authorization: Bearer <jwttoken> 的方式附加到Request上去。
5 OAuth2 & JWT
注意到我们在2. Token 元数据 这一小节中,OAuth2返回Token的元数据的JSON,以及OAuth2中的access_token对Client是不透明的字符串这件事,我们可以把access_token的元数据信息用JWT来编码以下,作为access_token的字符串内容,这样是不是就可以使得它对Client是透明的了。
比如我之前遇到的问题,在我使用access_token的时候有没有过期我并不知道,其实需要借助辅助的“expires_in”来检查,还有其scope是哪些,也需要额外的去查询,再比如这个access_token管理的用户是谁,也需要额外的查询,有了JWT呢,可以把这些都打包进去,比如:
{
"sub":"linianhui",
"scope":"1419356238",
"exp":123456789,
}
然后生成一个这样的jwt字符串 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsaW5pYW5odWkiLCJzY29wZSI6IjE0MTkzNTYyMzgiLCJleHAiOjEyMzQ1Njc4OX0.ASu85ohHMSOhnxbJSJI4OKLsPlbjPs7th0Xw5-b4l1A 作为access_token的值,感觉一下子就方便了好多吧。
6 总结
OAuth2在RFC6749中并未完整的提供一些问题的解决方案,而是附加了一些相关的RFC来解决这些问题,其实除了本文中提到的2个问题点之外,还有一些其他可以优化的地方存在(比如服务发现:https://tools.ietf.org/html/draft-ietf-oauth-discovery-06),From Post Response Mode :http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html),这些点在后续的OIDC的文章中再做介绍吧,感兴趣的可以看一看http://openid.net/connect/中关于OAuth2的另外一些相关扩展标准草案,这些标准也是OIDC所需要的一些可选支持;以及OAuth相关扩展草案:https://datatracker.ietf.org/wg/oauth/charter/。另外在一些场景下,使用JWT来使得OAuth2的提供自包含的Token还是一件很方便的事情的。
以上内容均是个人的一些理解,如果错误之处,欢迎指正!
7 参考
JSON协议:RFC7159 - The JavaScript Object Notation (JSON) Data Interchange Format
OAuth2 扩展协议:
RFC7009 - OAuth 2.0 Token Revocation
RFC7662 - OAuth 2.0 Token Introspection
OAuth相关扩展草案:
https://datatracker.ietf.org/wg/oauth/charter/
https://tools.ietf.org/wg/oauth/
JWT相关协议族:
RFC7515 - JSON Web Signature (JWS)
RFC7516 - JSON Web Encryption (JWE)
RFC7518 - JSON Web Algorithms (JWA)
RFC7519 - JSON Web Token (JWT)
JWT官方站点:https://jwt.io
Claims:https://en.wikipedia.org/wiki/Claims-based_identity
JWT注册的的一组Claims : https://www.iana.org/assignments/jwt/jwt.xhtml
[认证授权] 2.OAuth2授权(续) & JWT(JSON Web Token)的更多相关文章
- [认证授权] 2.OAuth2(续) & JSON Web Token
0. RFC6749还有哪些可以完善的? 0.1. 撤销Token 在上篇[认证授权] 1.OAuth2授权中介绍到了OAuth2可以帮我们解决第三方Client访问受保护资源的问题,但是只提供了如何 ...
- 温故知新,.Net Core遇见JWT(JSON Web Token)授权机制方案
什么是JWT JWT (JSON Web Token) 是一个开放标准,它定义了一种以紧凑和自包含的方法,用于在双方之间安全地传输编码为JSON对象的信息. 因此,简单来说,它是JSON格式的加密字符 ...
- [更新]一份包含: 采用RSA JWT(Json Web Token, RSA加密)的OAUTH2.0,HTTP BASIC,本地数据库验证,Windows域验证,单点登录的Spring Security配置文件
没有任何注释,表怪我(¬_¬) 更新: 2016.05.29: 将AuthorizationServer和ResourceServer分开配置 2016.05.29: Token获取采用Http Ba ...
- JWT(Json Web Token)认证
目录 JWT(Json Web Token) JWT的数据结构 JWT的用法 JWT验证流程
- 什么是JWT(Json Web Token)
什么是 JWT (Json Web Token) 用户认证是计算机安全领域一个永恒的热点话题. JWT 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). 该to ...
- Java JWT: JSON Web Token
Java JWT: JSON Web Token for Java and Android JJWT aims to be the easiest to use and understand libr ...
- JWT(JSON Web Token) 【转载】
JWT(JSON Web Token) 什么叫JWTJSON Web Token(JWT)是目前最流行的跨域身份验证解决方案. 一般来说,互联网用户认证是这样子的. 1.用户向服务器发送用户名和密码. ...
- ( 转 ) 什么是 JWT -- JSON WEB TOKEN
什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点 ...
- 5分钟搞懂:JWT(Json Web Token)
https://www.qikegu.com/easy-understanding/892 JWT 基于token的用户认证原理:让用户输入账号和密码,认证通过后获得一个token(令牌),在toke ...
- 如何在SpringBoot中集成JWT(JSON Web Token)鉴权
这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...
随机推荐
- VS2017搭建驱动开发环境WDK
先安装VS2017,然后在安装WDK,WDK会自动关联到VS2017中,不用你任何操作,自动在新建项目中可以找到驱动开发. 如果以上安装完成后,在VS2017中新建项目中没有发现WDK,那么需要进行修 ...
- 最短路问题之Bellman-ford算法
题目: 最短路:给定两个顶点,在以这两个点为起点和终点的路径中,边的权值和最小的路径.考虑权值为点之间的距离. 单源最短路问题,Bellman-ford算法 思路:每次循环检查所有边,可优化. 应用于 ...
- jquery ajax跨域请求后台的简单例子
一.简介AJAX 是与服务器交换数据的技术,它在不重载全部页面的情况下,实现了对部分网页的更新. ajax() 方法通过 HTTP 请求加载远程数据. 该方法是 jQuery 底层 AJAX 实现.简 ...
- 构造方法、This关键字、静态与封装的特性与作用
1.构造方法 构造方法是一种特殊的方法,专门用于构造/实例化对象. 构造方法根据是否有参数分为无参构造方法和有参构造方法. 1.1无参构造方法 无参构造方法就是构造方法没有任何参数.无参构造方法在创建 ...
- 强化学习(九)Deep Q-Learning进阶之Nature DQN
在强化学习(八)价值函数的近似表示与Deep Q-Learning中,我们讲到了Deep Q-Learning(NIPS 2013)的算法和代码,在这个算法基础上,有很多Deep Q-Learning ...
- centos7下搜狗输入法的安装教程
相信用过centos自带的输入法的朋友都会感叹这也实在是太难用了吧,使用拼音打出来的词总是不能在前几个匹配到,即使是一些常用词也是如此,简直无法忍受跟个zz似的.吐槽完了,这里给出centos7下搜狗 ...
- Asp.NetCore轻松学-业务重点-实现一个简单的手机号码验证
前言 本文纯干货,直接拿走使用,不用付费.在业务开发中,手机号码验证是我们常常需要面对的问题,目前市场上各种各样的手机号码验证方式,比如正则表达式等等,本文结合实际业务场景,在业务级别对手机号 ...
- 深入理解Linux内核 学习笔记(1)
1.用户和用户组 每个用户是一个或多个用户组的一名成员,组由唯一的用户组标识符(user group ID)标识.每个文件的相关权限也恰好与一个组相对应. root为超级用户, 2.模块 为了达到微内 ...
- RDIFramework.NET V3.3 Web版新增系统公告、系统新闻模块方便需要的客户
1.系统新闻功能描述 在RDIFramework.NET V3.3版本中新增了系统新闻模块,用户可以根据实际情况做相应应用,如用在内部业务系统的展示中或网站上新闻的展示.新闻可以分类进行管理,非常的实 ...
- Service Worker基础知识整理
Service Worker是什么 service worker 是独立于当前页面的一段运行在浏览器后台进程里的脚本.它的特性将包括推送消息,背景后台同步, geofencing(地理围栏定位),拦截 ...