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个重要的概念:

  1. 授权者小明:表示是小明授权,而不是隔壁老王。
  2. 被授权者在线打印并且包邮的网站:表示授权给指定的网站,而不是其他的比如1024.com之类的网站(你懂的。。。)。
  3. 小明自己的QQ空间:表示让被授权者访问自己的信息,而不是隔壁老王的信息,小明也没这权限来着,不然隔壁王婶夜不答应吧。。。
  4. 相册:表示你可以访问我的相册,而不是我的日志,我的其他信息。

那么如何得到获得上面提到的这些附加的信息呢?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 czZCaGRSa3F0MzpnWDFmQmF0M2JW

token=45ghiukldjahdnhzdauz&token_type_hint=refresh_token

其中各项含义如下:

  1. /revoke:是Authorization Server需要提供的API地址,Client使用Post方式请求这个地址。
  2. Content-Type: application/x-www-form-urlencoded:固定此格式。
  3. Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW:访问受保护资源的授权凭证。
  4. token:必选,可以是access_token或者refresh_token的内容。
  5. 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.123483

token=2YotnFZFEjr1zCsicMWpAA&token_type_hint=access_token

看起来和上面的撤销Token的请求差不多,其中各项含义如下:

  1. /introspect:是Authorization Server需要提供的API地址,Client使用Post方式请求这个地址。
  2. Accept:application/json:表示Authorization Server需要返回一个JSON格式的数据。
  3. Content-Type: application/x-www-form-urlencoded:固定此格式。
  4. Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW:访问受保护资源的授权凭证。
  5. token:必选,可以是access_token或者refresh_token的内容。
  6. 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中定义的,参考链接有详细的介绍):

  1. active:必须的。表示token是否还是有效的。
  2. client_id:可选的。表示token所属的Client。比如上面的在线打印并且包邮的网站
  3. token_type:可选的。表示token的类型。对应传递的token_type_hint。
  4. user_name:可选的。表示token的授权者的名字。比如上面的小明
  5. scope:可选的。和上篇5.1.1 Authorization Request中的可选参数scope对应,表示授权给Client访问的范围,比如是相册,而不是小明的日志以及其他受保护资源。
  6. sub:可选的。token所属的资源拥有者的唯一标识,JWT定义的。也就是小明的唯一标识符。
  7. aud:可选的。token颁发给谁的,JWT定义的。
  8. iss:可选的。token的颁发者,JWT定义的。
  9. exp:可选的。token的过期时间,JWT定义的。
  10. iat:可选的。iss颁发token的时间,JWT定义的。
  11. nbf:可选的。token不会在这个时间之前被使用,JWT定义的。
  12. jti:可选的。token的唯一标识,JWT定义的。
  13. 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,但并不是必选的,常用的有:

  1. iss(Issuer签发者)
  2. sub(subject签发给的受众,在Issuer范围内是唯一的)
  3. aud(Audience接收方)
  4. exp(Expiration Time过期时间)
  5. 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)

RFC7517 - JSON Web Key (JWK)

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)的更多相关文章

  1. [认证授权] 2.OAuth2(续) & JSON Web Token

    0. RFC6749还有哪些可以完善的? 0.1. 撤销Token 在上篇[认证授权] 1.OAuth2授权中介绍到了OAuth2可以帮我们解决第三方Client访问受保护资源的问题,但是只提供了如何 ...

  2. 温故知新,.Net Core遇见JWT(JSON Web Token)授权机制方案

    什么是JWT JWT (JSON Web Token) 是一个开放标准,它定义了一种以紧凑和自包含的方法,用于在双方之间安全地传输编码为JSON对象的信息. 因此,简单来说,它是JSON格式的加密字符 ...

  3. [更新]一份包含: 采用RSA JWT(Json Web Token, RSA加密)的OAUTH2.0,HTTP BASIC,本地数据库验证,Windows域验证,单点登录的Spring Security配置文件

    没有任何注释,表怪我(¬_¬) 更新: 2016.05.29: 将AuthorizationServer和ResourceServer分开配置 2016.05.29: Token获取采用Http Ba ...

  4. JWT(Json Web Token)认证

    目录 JWT(Json Web Token) JWT的数据结构 JWT的用法 JWT验证流程

  5. 什么是JWT(Json Web Token)

    什么是 JWT (Json Web Token) 用户认证是计算机安全领域一个永恒的热点话题. JWT 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). 该to ...

  6. 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 ...

  7. JWT(JSON Web Token) 【转载】

    JWT(JSON Web Token) 什么叫JWTJSON Web Token(JWT)是目前最流行的跨域身份验证解决方案. 一般来说,互联网用户认证是这样子的. 1.用户向服务器发送用户名和密码. ...

  8. ( 转 ) 什么是 JWT -- JSON WEB TOKEN

    什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点 ...

  9. 5分钟搞懂:JWT(Json Web Token)

    https://www.qikegu.com/easy-understanding/892 JWT 基于token的用户认证原理:让用户输入账号和密码,认证通过后获得一个token(令牌),在toke ...

  10. 如何在SpringBoot中集成JWT(JSON Web Token)鉴权

    这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...

随机推荐

  1. VS2017搭建驱动开发环境WDK

    先安装VS2017,然后在安装WDK,WDK会自动关联到VS2017中,不用你任何操作,自动在新建项目中可以找到驱动开发. 如果以上安装完成后,在VS2017中新建项目中没有发现WDK,那么需要进行修 ...

  2. 最短路问题之Bellman-ford算法

    题目: 最短路:给定两个顶点,在以这两个点为起点和终点的路径中,边的权值和最小的路径.考虑权值为点之间的距离. 单源最短路问题,Bellman-ford算法 思路:每次循环检查所有边,可优化. 应用于 ...

  3. jquery ajax跨域请求后台的简单例子

    一.简介AJAX 是与服务器交换数据的技术,它在不重载全部页面的情况下,实现了对部分网页的更新. ajax() 方法通过 HTTP 请求加载远程数据. 该方法是 jQuery 底层 AJAX 实现.简 ...

  4. 构造方法、This关键字、静态与封装的特性与作用

    1.构造方法 构造方法是一种特殊的方法,专门用于构造/实例化对象. 构造方法根据是否有参数分为无参构造方法和有参构造方法. 1.1无参构造方法 无参构造方法就是构造方法没有任何参数.无参构造方法在创建 ...

  5. 强化学习(九)Deep Q-Learning进阶之Nature DQN

    在强化学习(八)价值函数的近似表示与Deep Q-Learning中,我们讲到了Deep Q-Learning(NIPS 2013)的算法和代码,在这个算法基础上,有很多Deep Q-Learning ...

  6. centos7下搜狗输入法的安装教程

    相信用过centos自带的输入法的朋友都会感叹这也实在是太难用了吧,使用拼音打出来的词总是不能在前几个匹配到,即使是一些常用词也是如此,简直无法忍受跟个zz似的.吐槽完了,这里给出centos7下搜狗 ...

  7. Asp.NetCore轻松学-业务重点-实现一个简单的手机号码验证

    前言     本文纯干货,直接拿走使用,不用付费.在业务开发中,手机号码验证是我们常常需要面对的问题,目前市场上各种各样的手机号码验证方式,比如正则表达式等等,本文结合实际业务场景,在业务级别对手机号 ...

  8. 深入理解Linux内核 学习笔记(1)

    1.用户和用户组 每个用户是一个或多个用户组的一名成员,组由唯一的用户组标识符(user group ID)标识.每个文件的相关权限也恰好与一个组相对应. root为超级用户, 2.模块 为了达到微内 ...

  9. RDIFramework.NET V3.3 Web版新增系统公告、系统新闻模块方便需要的客户

    1.系统新闻功能描述 在RDIFramework.NET V3.3版本中新增了系统新闻模块,用户可以根据实际情况做相应应用,如用在内部业务系统的展示中或网站上新闻的展示.新闻可以分类进行管理,非常的实 ...

  10. Service Worker基础知识整理

    Service Worker是什么 service worker 是独立于当前页面的一段运行在浏览器后台进程里的脚本.它的特性将包括推送消息,背景后台同步, geofencing(地理围栏定位),拦截 ...