0 目錄

認(rèn)證授權(quán)系列:http://www.cnblogs.com/linianhui/category/929878.html

1 RFC6749還有哪些可以完善的?

1.1 撤銷Token

在上篇[認(rèn)證授權(quán)] 1.OAuth2授權(quán) 中介紹到了OAuth2可以幫我們解決第三方Client訪問受保護資源的問題,但是只提供了如何獲得access_token,并未說明怎么來撤銷一個access_token。關(guān)于這部分OAuth2單獨定義了一個RFC7009 - OAuth 2.0 Token Revocation來解決撤銷Token問題。

1.2 Token對Client的不透明問題

OAuth2提供的“access_token"是一個對Client不透明的字符串,盡管有"scope","expires_in"和"refresh_token"來輔助,但也是不完善的且分散的信息。還拿上一篇的小明來舉例,“小明授權(quán)在線打印并且包郵的網(wǎng)站訪問自己的QQ空間相冊”。雙引號里面的這句話其中有4個重要的概念:

  1. 授權(quán)者小明:表示是小明授權(quán),而不是隔壁老王。

  2. 被授權(quán)者在線打印并且包郵的網(wǎng)站:表示授權(quán)給指定的網(wǎng)站,而不是其他的比如1024.com之類的網(wǎng)站(你懂的。。。)。

  3. 小明自己的QQ空間:表示讓被授權(quán)者訪問自己的信息,而不是隔壁老王的信息,小明也沒這權(quán)限來著,不然隔壁王嬸夜不答應(yīng)吧。。。

  4. 相冊:表示你可以訪問我的相冊,而不是我的日志,我的其他信息。

那么如何得到獲得上面提到的這些附加的信息呢?OAuth2又單獨提供了一個RFC7662 -OAuth 2.0 Token Introspection來解決Token的描述信息不完整的問題。

這些信息不但對Client不透明,對于資源服務(wù)器來說也是不透明的,比如授權(quán)服務(wù)器和資源服務(wù)器是獨立部署的,而OAuth2又要求資源服務(wù)器要對access token做校驗,沒有這些信息如何校驗?zāi)兀砍窃赼ccess token的db存儲層面做共享,但是作為一個運行在互聯(lián)網(wǎng)規(guī)模上的網(wǎng)絡(luò)環(huán)境下的協(xié)議,這種假設(shè)是無法支撐互聯(lián)網(wǎng)規(guī)模的環(huán)境的。

2 OAuth2 Token 撤銷(RFC7009 - OAuth2 Token Revocation)

簡單來說,這個協(xié)議規(guī)定了一個Authorization server提供一個怎樣的API來供Client撤銷access_token或者refresh_token。

比如Client發(fā)起一個如下的請求:

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:訪問受保護資源的授權(quán)憑證。

  4. token:必選,可以是access_token或者refresh_token的內(nèi)容。

  5. token_type_hint:可選,表示token的類型,值為”access_token“或者"refresh_token"。

如果撤銷成功,則返回一個HTTP status code為200的響應(yīng)就可以了。

3 OAuth2 Token 元數(shù)據(jù)(RFC7662 - OAuth2 Token Introspection)

簡單的總結(jié)來說,這個規(guī)范是為OAuth2擴展了一個API接口(Introspection Endpoint),讓第三方Client可以查詢上面提到的那些信息(比如,access_token是否還有效,誰頒發(fā)的,頒發(fā)給誰的,scope又哪些等等的元數(shù)據(jù)信息)。

比如Client發(fā)起一個如下的請求:

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格式的數(shù)據(jù)。

  3. Content-Type: application/x-www-form-urlencoded:固定此格式。

  4. Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW:訪問受保護資源的授權(quán)憑證。

  5. token:必選,可以是access_token或者refresh_token的內(nèi)容。

  6. token_type_hint:可選,表示token的類型,值為”access_token“或者"refresh_token"。

如果請求成功,則會返回如下的信息:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

 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 }

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

JSON各項屬性含義如下(其中有些信息是在JSON Web Token中定義的,參考鏈接有詳細的介紹):

  1. active:必須的。表示token是否還是有效的。

  2. client_id:可選的。表示token所屬的Client。比如上面的在線打印并且包郵的網(wǎng)站

  3. token_type:可選的。表示token的類型。對應(yīng)傳遞的token_type_hint。

  4. user_name:可選的。表示token的授權(quán)者的名字。比如上面的小明。

  5. scope:可選的。和上篇5.1.1 Authorization Request中的可選參數(shù)scope對應(yīng),表示授權(quán)給Client訪問的范圍,比如是相冊,而不是小明的日志以及其他受保護資源。

  6. sub:可選的。token所屬的資源擁有者的唯一標(biāo)識,JWT定義的。也就是小明的唯一標(biāo)識符。

  7. aud:可選的。token頒發(fā)給誰的,JWT定義的。

  8. iss:可選的。token的頒發(fā)者,JWT定義的。

  9. exp:可選的。token的過期時間,JWT定義的。

  10. iat:可選的。iss頒發(fā)token的時間,JWT定義的。

  11. nbf:可選的。token不會在這個時間之前被使用,JWT定義的。

  12. jti:可選的。token的唯一標(biāo)識,JWT定義的。

  13. extension_field:可以自己擴展相關(guān)其他屬性。

其中大量的信息都是可選的信息,而且可以自己擴展需要的屬性信息,從這些屬性中就可以解決我們上面提到的access_token對于Client不透明的問題。

我們注意到其中有很多屬于JWT定義的屬性,那么這個JWT是什么東西?它解決了什么問題?

4 JSON Web Token (JWT)

簡單總結(jié)來說,JWT是一個定義一種緊湊的自包含的并且提供防篡改機制的傳遞數(shù)據(jù)的方式的標(biāo)準(zhǔn)協(xié)議。

我們先來看一個簡單的示例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Imxpbmlhbmh1aSJ9.hnOfZb95jFwQsYj3qlgFbUu1rKpfTE6AzgXZidEGGTk

就是這么一堆看起來像是亂碼一樣的字符串。JWT由3部分構(gòu)成:header.payload.signature,每個部分由“.”來分割開來。

4.1 Header

header是一個有效的JSON,其中通常包含了兩部分:token類型和加密算法。

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

對這個JSON采用base64編碼后就是第1部分eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9。

4.2 Payload

這一部分代表真正想要傳遞的數(shù)據(jù),包含一組Claims,其中JWT預(yù)定義了一些Claim(2. Token 元數(shù)據(jù) 這一節(jié)就用到一些JWT預(yù)定義的一些Cliam)后面會介紹。關(guān)于什么是Claim,可以參考文章末尾給的參考鏈接。

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

對這個JSON采用base64編碼后就是第2部分eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Imxpbmlhbmh1aSJ9。

4.3 Signature

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

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

使用header中指定的簽名算法對“header.payload”部分進行簽名,得到的第3部分hnOfZb95jFwQsYj3qlgFbUu1rKpfTE6AzgXZidEGGTk。然后組合成一個完整的JWT字符串,而接收方使用同樣的簽名算法來生成簽名,來判斷header和payload部分有沒有被篡改鍋,因為簽名的密鑰是只有通信雙方知道的,所以可以保證這部分信息不被第三方所篡改。

4.4 JWT的一些Claims

JWT規(guī)范中預(yù)先定義了一些Cliam,但并不是必選的,常用的有:

  1. iss(Issuer簽發(fā)者)。

  2. sub(subject簽發(fā)給的受眾,在Issuer范圍內(nèi)是唯一的)。

  3. aud(Audience接收方)

  4. exp(Expiration Time過期時間)。

  5. iat(Issued At簽發(fā)時間)等等。

更完整的一些Claim列表參見:https://www.iana.org/assignments/jwt/jwt.xhtml

如果上面這些仍無法滿足自己的需要,則可以自定義一些來使用。

4.5 JWT 應(yīng)用場景

由于其采用base64來進行編碼,使得它可以安全的用在一些僅限ASCII的地方傳遞信息,比如URL的querystring中。

比如用戶登陸后,可以把用戶的一些屬性信息(用戶標(biāo)識,是否是管理員,權(quán)限有哪些等等可以公開的信息)用JWT編碼存儲在cookie中,由于其自包含的性質(zhì),每次服務(wù)器讀取到Cookie的時候就可以解析到當(dāng)前用戶對應(yīng)的屬性信息,而不必再次去查詢數(shù)據(jù)庫。如果Cookie中每次都發(fā)送浪費帶寬,也可以用 Authorization: Bearer <jwttoken> 的方式附加到Request上去。

5 OAuth2 & JWT

注意到我們在2. Token 元數(shù)據(jù) 這一小節(jié)中,OAuth2返回Token的元數(shù)據(jù)的JSON,以及OAuth2中的access_token對Client是不透明的字符串這件事,我們可以把access_token的元數(shù)據(jù)信息用JWT來編碼以下,作為access_token的字符串內(nèi)容,這樣是不是就可以使得它對Client是透明的了。

比如我之前遇到的問題,在我使用access_token的時候有沒有過期我并不知道,其實需要借助輔助的“expires_in”來檢查,還有其scope是哪些,也需要額外的去查詢,再比如這個access_token管理的用戶是誰,也需要額外的查詢,有了JWT呢,可以把這些都打包進去,比如:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

{
    "sub":"linianhui",
    "scope":"1419356238",
    "exp":123456789,
}

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

然后生成一個這樣的jwt字符串 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsaW5pYW5odWkiLCJzY29wZSI6IjE0MTkzNTYyMzgiLCJleHAiOjEyMzQ1Njc4OX0.ASu85ohHMSOhnxbJSJI4OKLsPlbjPs7th0Xw5-b4l1A 作為access_token的值,感覺一下子就方便了好多吧。

6 總結(jié)

OAuth2在RFC6749中并未完整的提供一些問題的解決方案,而是附加了一些相關(guān)的RFC來解決這些問題,其實除了本文中提到的2個問題點之外,還有一些其他可以優(yōu)化的地方存在(比如服務(wù)發(fā)現(xiàn):https://tools.ietf.org/html/draft-ietf-oauth-discovery-06),F(xiàn)rom Post Response Mode :http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html),這些點在后續(xù)的OIDC的文章中再做介紹吧,感興趣的可以看一看http://openid.net/connect/中關(guān)于OAuth2的另外一些相關(guān)擴展標(biāo)準(zhǔn)草案,這些標(biāo)準(zhǔn)也是OIDC所需要的一些可選支持;以及OAuth相關(guān)擴展草案:https://datatracker.ietf.org/wg/oauth/charter/。另外在一些場景下,使用JWT來使得OAuth2的提供自包含的Token還是一件很方便的事情的。

以上內(nèi)容均是個人的一些理解,如果錯誤之處,歡迎指正!

7 參考

JSON協(xié)議:RFC7159 - The JavaScript Object Notation (JSON) Data Interchange Format

OAuth2 擴展協(xié)議:

RFC7009 - OAuth 2.0 Token Revocation

RFC7662 - OAuth 2.0 Token Introspection

OAuth相關(guān)擴展草案:https://datatracker.ietf.org/wg/oauth/charter/

JWT相關(guān)協(xié)議族:

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

出處:http://linianhui.cnblogs.com

本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。

http://www.cnblogs.com/linianhui/p/oauth2-extensions-protocol-and-json-web-token.html