OAuth2中的access_token

之前的一篇文章OAuth2的原理和应用对OAuth2进行了简单的介绍。OAuth2的关键技术就是令牌 (access token),本文着重讨论有关令牌的一些知识。

Token的数据对客户端是不透明的

OAuth2提供的“access_token”仅仅是一个字符串,尽管有"scope","expires_in"和"refresh_token"来辅助,但也是不完善的且分散的信息。拿OAuth2的原理和应用中的实例来说,有四个重要的概念:

  1. 用户(Resource Owner)。
  2. 被授权的应用"云冲印"(客户端)。
  3. 资源服务器,Google
  4. 认证服务器,也是Google
    这些信息应该通过某种方式同令牌关联起来,但是由于实际的实现中access_token没有包含这些信息,也就是说这些信息对于客户端来说是不透明的。

为此,OAuth2又单独提供了一个RFC7662 -OAuth 2.0 Token Introspection来解决Token的描述信息不完整的问题。

OAuth2 Token 元数据(RFC7662 - OAuth2 Token Introspection)

简单的总结来说,这个规范是为OAuth2扩展了一个API接口(Introspection Endpoint),让第三方客户端可以查询上面提到的那些信息(比如,access_token是否还有效,谁颁发的,颁发给谁的,scope又哪些等等的元数据信息)。

比如客户端发起一个如下的请求:

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

其中各项含义如下:

  • /introspect:是Authorization Server需要提供的API地址,Client使用Post方式请求这个地址。
  • Accept:application/json:表示Authorization Server需要返回一个JSON格式的数据。
  • Content-Type: application/x-www-form-urlencoded:固定此格式。
  • Authorization: Bearer 23410913-abewfq.123483:其中"Bearer "是固定的在access_token前面的头部信息。为了防止token扫描攻击,这个API仍然需要某种形式的授权保护,例如bearer token【1】。

To prevent token scanning attacks, the endpoint MUST also require
some form of authorization to access this endpoint, such as client
authentication as described in OAuth 2.0 [[RFC6749](https://tools.ietf.org/html/rfc6749 ""The OAuth 2.0 Authorization Framework"")] or a separate
OAuth 2.0 access token such as the bearer token described in OAuth
2.0 Bearer Token Usage [RFC6750].

  • token:必选,可以是access_token或者refresh_token的内容。
  • 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 Web Token (JWT)

OAuth2返回Token的元数据的JSON,但是OAuth2中的access_token对客户端仍然是不透明的字符串,如果可以把access_token的元数据信息作为access_token的字符串内容,这样是不是就可以使得它对Client是透明的了?
这样做有两个问题:

  1. 令牌的信息可能会被篡改。
  2. 在仅限ASCII的地方,传递token信息可能会有问题。

为了解决这些问题,JWT出现了。

定义

简单总结来说,JWT是一个定义一种紧凑的,自包含的并且提供防篡改机制的传递数据的方式的标准协议。

我们先来看一个简单的示例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Imxpbmlhbmh1aSJ9.hnOfZb95jFwQsYj3qlgFbUu1rKpfTE6AzgXZidEGGTk

就是这么一堆看起来像是乱码一样的字符串。JWT由3部分构成:header.payload.signature,每个部分由“.”来分割开来。

header

header是一个有效的JSON,其中通常包含了两部分:token类型和签名算法。

{
  "alg": "HS256",
  "typ": "JWT"
}

对这个JSON采用base64编码后就是第1部分

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9。

Payload

这一部分代表真正想要传递的数据,包含一组Claims【2】,其中JWT预定义了一些Claim:

{
  "sub": "1234567890",
  "name": "linianhui"
}

对这个JSON采用base64编码后就是第2部分

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Imxpbmlhbmh1aSJ9。

Signature

这一部分是可选的,由于前面Header和Payload部分是明文的信息,所以这一部分的意义在于保障信息不被篡改用的,生成这部分的方式如下:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

token生成方使用header中指定的签名算法对“header.payload”部分进行签名,得到的第3部分hnOfZb95jFwQsYj3qlgFbUu1rKpfTE6AzgXZidEGGTk,然后组合成一个完整的JWT字符串 . 而token消费方在拿到token后, 使用同样的签名算法来生成签名,用来判断header和payload部分有没有被篡改过,因为签名的密钥是只有通信双方知道的,所以可以保证这部分信息不被第三方所篡改。

JWT 应用场景

由于其采用base64来进行编码,使得它可以安全的用在一些仅限ASCII的地方传递信息,比如URL的querystring中。

比如用户登陆后,可以把用户的一些属性信息(用户标识,是否是管理员,权限有哪些等等可以公开的信息)用JWT编码存储在cookie中,由于其自包含的性质,每次服务器读取到Cookie的时候就可以解析到当前用户对应的属性信息,而不必再次去查询数据库。如果Cookie中每次都发送浪费带宽,也可以用 Authorization: Bearer <jwttoken> 的方式附加到Request上去。

OAuth2 & JWT

我们可以把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的值,感觉一下子就方便了好多。
本文的内容主要来自:
[认证 & 授权] 2. OAuth2授权(续) & JWT(JSON Web Token)
【1】https://tools.ietf.org/html/rfc7662
【2】https://www.iana.org/assignments/jwt/jwt.xhtml

你可能感兴趣的:(OAuth2中的access_token)