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(续) & JSON Web Token的更多相关文章

  1. 理解JWT(JSON Web Token)认证及python实践

    原文:https://segmentfault.com/a/1190000010312468?utm_source=tag-newest 几种常用的认证机制 HTTP Basic Auth HTTP ...

  2. 一分钟简单了解 JSON Web Token

    JSON Web Token(JWT)是一个开放的标准(RFC 7519),它定义了一个紧凑且自包含的方式,用于在各方之间作为 JSON 对象安全地传输信息.由于此信息是经过数字签名的,因此可以被验证 ...

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

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

  4. JWT(JSON WEB TOKEN) / oauth2 / SSL

    1: JWT: 为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景.JWT的声明一般被 ...

  5. 理解JWT(JSON Web Token)认证

    理解JWT(JSON Web Token)认证 最近想做个小程序,需要用到授权认证流程.以前项目都是用的 OAuth2 认证,但是Sanic 使用OAuth2 不太方便,就想试一下 JWT 的认证方式 ...

  6. 把旧系统迁移到.Net Core 2.0 日记 (18) --JWT 认证(Json Web Token)

    我们最常用的认证系统是Cookie认证,通常用一般需要人工登录的系统,用户访问授权范围的url时,会自动Redirect到Account/Login,登录后把认证结果存在cookie里. 系统只要找到 ...

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

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

  8. JWT(Json web token)认证详解

    JWT(Json web token)认证详解 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该to ...

  9. JWT—JSON Web Token - 理解JWT网络间应用用户安全认证交互设计

    原文地址:http://blog.leapoahead.com/2015/09/06/understanding-jwt/ 官网地址:https://jwt.io/ JSON Web Token(JW ...

随机推荐

  1. mac 终端简单指令

    pwd 当前工作目录 cd(不加参数) 进root cd(folder) 进入文件夹 cd .. 上级目录 cd ~ 返回root cd - 返回上一个访问的目录 rm 文件名 删除 cat 文件名( ...

  2. 《汇编语言程序设计》——仿windows计算器

    <汇编语言程序设计> ——计算器程序设计 目录 一.     题目与目标 1.      题目 2.      学习目的 二.     分析与设计 1.      系统分析 2.      ...

  3. 3D Touch开发

    一.3d Touch 官方文档介绍 1.A user can now press your Home screen icon to immediately access functionality p ...

  4. WP8.1开发中找程序下的Assets文件夹

    这俩天在开发另一个程序时,遇到一个小问题:如何调用程序下的Assets文件夹及其下的文件和文件夹: 在网上找了两天,基本上是关于如何调用手机中库的方法,没找到有关介绍如何调用查找 编译前添加图片或其它 ...

  5. 用DotRas来连接VPN网络

    最近要用程序来不断的连接VPN(为什么要这样就不讨论了),开始用的是如下代码: public static bool ADSL() { bool flag = true; do { Console.W ...

  6. 规范 : loading display & ui-view loading

    angular 没有compile 完成的接口,最像的接口是$viewContentLoaded(router ui),但是一开始会开始跑,因为有ui-view 暂时解决方法是在body的loadin ...

  7. Foundation Kit介绍

    Cocoa实际上是由许多个不同的框架组成的,其中最常用于桌面端(OS X)应用程序的是Foundation和Application Kit.它包含了所有的用户界面对象和高级类.如果打算开发ios平台上 ...

  8. java程序员入门:英语好不好对编程到底有没有影响

    我想当码农,听说钱钱拿的多! 哦.是很有钱!么样? 可是我不会! 那你想么样?去学撒! 可是,我英语差-- 有多差??? 很差-- 那????? 关于英语水平对编程的影响,我们一起来看看啦!希望可以解 ...

  9. <c>----<choose><when><otherwise>

    <c:choose> <c:when test="${username== '1' && password== '2'}"> <jsp ...

  10. oracle expdp和impdp常用命令选项

    一.expdp导出数据库 1.按用户导出 expdp scott/tiger@orcl DIRECTORY=oracle_dmp dumpfile=bak.dmp schemas=scott vers ...