[认证授权] 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个重要的概念:

  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"。

如果请求成功,则会返回如下的信息:

 1 {
 2       "active": true,
 3       "client_id": "l238j323ds-23ij4",
 4       "token_type":"access_token",
 5       "username": "jdoe",
 6       "scope": "read write dolphin",
 7       "sub": "Z5O3upPC88QrAjx00dis",
 8       "aud": "https://protected.example.net/resource",
 9       "iss": "https://server.example.com/",
10       "exp": 1419356238,
11       "iat": 1419350238,
12       "nbf": 1419350238,
13       "jti": "abcdefg"
14       "extension_field": "twenty-seven"
15 }

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

作者:Blackheart

原文链接:https://www.cnblogs.com/linianhui/p/oauth2-extensions-protocol-and-json-web-token.html

原文地址:https://www.cnblogs.com/gongap/p/9310264.html

时间: 2024-10-10 09:15:31

[认证授权] 2.OAuth2授权(续) & JWT(JSON Web Token)的相关文章

什么是 JWT -- JSON WEB TOKEN

转自于:http://www.jianshu.com/p/576dbf44b2ae 什么是JWT Json web token(JWT)是为了网络应用环境间传递声明而执行的一种基于JSON的开发标准(RFC 7519),该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景.JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密. 起

深入浅出JWT(JSON Web Token )

原文:深入浅出JWT(JSON Web Token ) 1. JWT 介绍 JSON Web Token(JWT)是一个开放式标准(RFC 7519),它定义了一种紧凑(Compact)且自包含(Self-contained)的方式,用于在各方之间以JSON对象安全传输信息. 这些信息可以通过数字签名进行验证和信任. 可以使用秘密(使用HMAC算法)或使用RSA的公钥/私钥对对JWT进行签名. 虽然JWT可以加密以提供各方之间的保密性,但我们将重点关注已签名的令牌. 签名的令牌可以验证其中包含的

Go实战--golang中使用JWT(JSON Web Token)

http://blog.csdn.net/wangshubo1989/article/details/74529333 之前写过关于golang中如何使用cookie的博客: 实战–go中使用cookie 今天就来跟大家简单介绍一下golang中如何使用token,当然是要依赖一下github上的优秀的开源库了. 首先,要搞明白一个问题,token.cookie.session的区别. token.cookie.session的区别 Cookie Cookie总是保存在客户端中,按在客户端中的存

JWT(JSON Web Token) Java与.Net简单编码实现

参考 JWT(JSON WEB TOKENS)-一种无状态的认证机制 基于Token的WEB后台认证机制 各种语言版本的基于HMAC-SHA256的base64加密 Java与.Net实现实现 // java HMacsha256 private static final String MAC_INSTANCE_NAME = "HMacSHA256"; public static String Hmacsha256(String secret, String message) thro

JWT(JSON web Token)

JWT 资料汇总 1. 官网:http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#rfc.appendix.A.1 2. 多说http://dev.duoshuo.com/docs/501e6ce1cff715f71800000d 3. Open source, the implantation of JWT: https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki

JWT(JSON WEB TOKEN) 简易

HTML <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="serve

JSON Web Token (JWT) 实现与使用方法

1. JSON Web Token是什么 JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的.自包含的方式,用于作为JSON对象在各方之间安全地传输信息.该信息可以被验证和信任,因为它是数字签名的. 2. 什么时候你应该用JSON Web Tokens 下列场景中使用JSON Web Token是很有用的: Authorization (授权) : 这是使用JWT的最常见场景.一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由.服务

JWT(JSON Web Token) 多网站的单点登录,放弃session

多个网站之间的登录信息共享, 一种解决方案是基于cookie - session的登录认证方式,这种方式跨域比较复杂. 另一种替代方案是采用基于算法的认证方式, JWT(json web token)的方式. 参考链接: http://www.tuicool.com/articles/IRJnaa https://coderwall.com/p/8wrxfw/goodbye-php-sessions-hello-json-web-tokens 一.概念和定义 1.什么是jwt? Json web

什么是JWT(JSON WEB TOKEN)

什么是JWT Json web token(JWT)是为了网络应用环境间传递声明而执行的一种基于JSON的开发标准(RFC 7519),该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景.JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密. 起源 说起JWT,我们应该来谈一谈基于token的认证和传统的Session认证的区别