我之前的文章簡單的介紹了OAuth 2.0 (在這里: https://www.cnblogs.com/cgzl/p/9221488.html), 還不是很全.
這篇文章我要介紹一下 OpenID Connect.
OAuth 2.0 不是身份認證協議
OAuth 2.0 不是身份認證(Authentication)協議. 為什么有人會認為OAuth 2.0具有身份認證的功能? 這是因為OAuth2經常作為身份認證(Authentication)協議的一部分來使用. 例如在典型的OAuth2流程里, OAuth2經常會嵌入一些身份認證的事件.
那么身份認證(Authentication)是什么?
我們這里所說的身份認證就是指它可以告訴應用程序當前的用戶是誰, 還有這些用戶是否正在使用你的應用程序. 它是一種安全架構, 它可以告訴你用戶是他們所聲明的身份, 通常呢, 是通過提供一套安全憑據(例如用戶名和密碼)給應用程序來證明這一點.
而OAuth2則不管用戶這些東西, OAuth2的客戶端應用只考慮請求token, 得到token, 使用token訪問API. 它不關心誰給客戶端應用授權了, 也不關心是否有最終用戶.\
身份認證(Authentication) vs 授權(Authorization)
引用《OAuth 2.0 in Action》里面的一個比喻來解釋, 把身份認證看作是軟糖, 而授權是巧克力. 這兩種東西感覺略有相似, 但是本質上卻截然不同: 巧克力是一種原料, 而軟糖是一種糖果. 可以使用巧克力作為主要原料做出巧克力口味的糖果, 但是巧克力和軟糖絕不是等價的.
盡管巧克力可以單獨作為一種最終產品, 但在這個比喻里巧克力是一種非常有用原料, 它極具多樣性, 可以用來做蛋糕, 冰激凌, 雪糕等等.
在這個比喻里 OAuth 2.0 就是巧克力, 它是眾多web安全架構的一種多用途的基本成分.
而軟糖, 是一種糖果. 有一種特別可口的軟糖叫做巧克力軟糖. 很顯然, 巧克力在這種軟糖里是主要成分, 但是它還需要其它原料成分和一些關鍵的流程把巧克力轉化成巧克力軟糖.
制做出的產品是軟糖的形式, 它以巧克力為主要成分. 這叫使用巧克力來制作軟糖, 所以說巧克力不等價於軟糖.
在這個比喻里, 身份認證就更像軟糖, 它需要一些關鍵的組件和流程, 而卻要把這些組件和流程通過正確的組合起來並安全的使用, 針對這些組件和流程還是有很多的選項的.
可以說我們要制作巧克力軟糖, 也就是需要一個基於OAuth2的身份認證協議. 而OpenID Connect就是這樣的開放標准, 它可以工作於不同的身份供應商之間. OpenID Connect 基於 OAuth 2.0, 在此之上, 它添加了一些組件來提供身份認證的能力.
OpenID Connect的官方定義是: OpenID Connect是建立在OAuth 2.0協議上的一個簡單的身份標識層, OpenID Connect 兼容 OAuth 2.0.
OAuth 2.0與身份認證協議的角色映射
想要基於OAuth2構建身份認證協議, 那么就需要把OAuth2里面的那些角色映射到身份認證的事務里面.
在OAuth2里面, 資源所有者(Resource Owner)和客戶端應用(Client)經常在一起工作, 因為客戶端應用代表了資源所有者. 而授權服務器(Authorization Server)和被保護的資源(Protected Resource)經常在一起, 因為授權服務器生成token, 而被保護的資源接收token. 所以說在最終用戶/客戶端應用 與 授權服務器/被保護資源 之前存在一個安全和信任的邊界, 而OAuth2就是用來跨越這個邊界的協議.
而在身份認證的事務里, 最終用戶使用身份提供商(Identity Provider, IdP)登錄到依賴方(Relying Party, RP, 可以理解為客戶端).
總結一下前面這段話:
OAuth2里可以分為兩部分: 1.資源所有者/客戶端應用, 2.授權服務器/被保護資源.
身份認證協議里也是兩大部分: 1.依賴方, 2.身份提供商.
所以考慮這樣映射:
- OAuth2里的授權服務器/被保護資源 ---- 身份認證協議里的身份提供商進行映射
- OAuth2里面的資源所有者 ---- 身份認證協議里的最終用戶
- OAuth2的客戶端應用 ---- 身份認證協議里的依賴方(RP).
OAuth2里, 資源所有者的權限會委派給客戶端應用, 但這時該權限對應的被保護資源就是他們自己的身份信息. 也就是說他們授權給依賴方(RP), 讓其可以知道現在是誰在使用應用, 而這就是身份認證事務本質.
依賴方現在就可以知道是誰在使用系統並且他們是如何登錄進來的. 不過這里還需要用到另外一種token, 叫做ID token, 這種token攜帶着身份認證事件本身的信息.
那么為什么不使用OAuth2里的access token把這些事都一次性解決了呢?
因為首先access token不含有任何關於身份認證的信息; 其次access token的生命期可能會非常的長, 即使用戶離開了它仍有可能有效, 它還有可能被用於無最終用戶參與的情況; 還有一種情況就是access token可能會被其它的客戶端應用借用. 所以, 無論客戶端是如何得到的access token, 它都無法從access token里得到最終用戶的信息以及最終用戶的身份認證狀態.
在OAuth2里, access token不是為客戶端准備的, 它對於客戶端應該是不透明的, 但是客戶端也需要從access token得到一些用戶信息. 實際上客戶端應用只是access token的展示者, access token真正的目標觀眾是被保護的資源.
在OpenID Connect里, 這個第二個叫做ID Token, 它會和access token一同發送給客戶端應用.
OpenID Connect
OpenID Connect是由OpenID基金會於2014年發布的一個開放標准, 簡單的說就是, 它使用OAuth2來進行身份認證. OpenID Connect直接構建於OAuth2.0的基礎之上, 與其兼容. 通常OpenID Connect是和OAuth2一同部署來使用的.
OpenID Connect的整體抽象流程如下圖所示:
1. 依賴發(RP)發送請求到OpenID提供商(OP, 也就是身份提供商).
2. OpenID提供商驗證最終用戶的身份, 並獲得了用戶委派的授權
3. OpenID提供商返回響應, 里面帶着ID Token, 也通常帶着Access Token.
4. 依賴方現在可以使用Access Token發送請求到用戶信息的端點.
5. 用戶信息端點返回用戶的聲明(claims, 相當於是用戶的信息).
OpenID Connect的ID Token 和用戶信息端點以后在使用Identity Server 4的時候在進行介紹.
身份認證
OpenID Connect 會負責身份認證這個動作, 也就是把最終用戶登錄到系統, 或者判斷最終用戶是否已經登錄了. OpenID Connect會通過一種安全的方式從服務器把身份認證的結果返回給客戶端, 這樣客戶端就可以依賴於它了. 也是因為這個原因, 客戶端被稱為了依賴方(RP). 這個身份認證的結果就是ID Token.
OpenID Connect身份認證有三個路徑(三個流程, flow): Authorization Code 流程, Implicit 流程, Hybrid 流程.
Authorization Code Flow
在Authorization Code 流程里, 一個授權碼(Authorization Code)會被返回給客戶端. 這個授權碼可以被直接用來交換ID Token和Access Token. 該流程也可以在客戶端使用授權碼兌換Access Token之前對其身份認證. 但是該流程要求客戶端的身份認證動作在后台使用client id和secret來獲得tokens, 這樣就不會把tokens暴露給瀏覽器或其它可訪問瀏覽器的惡意應用了.
這種流程要求客戶端應用可以安全的在它和授權服務器之間維護客戶端的secret, 也就是說只適合這樣的客戶端應用.
它還適合於長時間的訪問(通過refresh token).
Authorization Code流程的授權碼來自於授權端點, 而所有的tokens都來自於Token端點.
Authorization Code流程的步驟如下:
- 客戶端准備身份認證請求, 請求里包含所需的參數
- 客戶端發送請求到授權服務器
- 授權服務器對最終用戶進行身份認證
- 授權服務器獲得最終用戶的同意/授權
- 授權服務器把最終用戶發送回客戶端, 同時帶着授權碼
- 客戶端使用授權碼向Token端點請求一個響應
- 客戶端接收到響應, 響應的body里面包含着ID Token 和 Access Token
- 客戶端驗證ID Token, 並獲得用戶的一些身份信息.
Implicit Flow
Implicit流程在請求token的時候不需要明確的客戶端身份認證, 它使用重定向URI的方式來驗證客戶端的身份. 因為這一點, refresh token也就無法使用了, 這同樣也不適合於長時間有效的access token.
在Implicit流程里, 所有的tokens都來自於授權端點, 而Token端點並沒有用到.
該流程主要用於瀏覽器內的應用, Access Token和ID Token一同被直接返回給客戶端. 因為這個原因, 這些tokens也會暴露於最終用戶和可以訪問該瀏覽器的其它應用了.
它並不適合於長時間的訪問.
Implicit流程的步驟如下:
- 客戶端准備身份認證請求, 請求里包含所需的參數
- 客戶端發送請求到授權服務器
- 授權服務器對最終用戶進行身份認證
- 授權服務器獲得最終用戶的同意/授權
- 授權服務器把最終用戶發送回客戶端, 同時帶着ID Token. 如果也請求了Access Token的話, 那么Access Token也會一同返回.
- 客戶端驗證ID Token, 並獲得用戶的一些身份信息.
Hybrid Flow
Hybrid流程是前兩者的混合, 在該流程里, 有一些tokens和授權碼來自於授權端點, 而另外一些tokens則來自於Token端點.
該流程允許客戶端立即使用ID Token, 並且只需要一次往返即可獲得授權碼.
這種流程也要求客戶端應用可以安全的維護secret.
它也適合於長時間的訪問.
Hybrid流程的步驟如下:
- 客戶端准備身份認證請求, 請求里包含所需的參數
- 客戶端發送請求到授權服務器
- 授權服務器對最終用戶進行身份認證
- 授權服務器獲得最終用戶的同意/授權
- 授權服務器把最終用戶發送回客戶端, 同時帶着授權碼, 根據響應類型的不同, 也可能還帶着一個或者多個其它的參數.
- 客戶端使用授權碼向Token端點請求一個響應
- 客戶端接收到響應, 響應的body里面包含着ID Token 和 Access Token
- 客戶端驗證ID Token, 並獲得用戶的一些身份信息.
三種流程特點的比較:
Authorization Code Flow | Implicit Flow | Hybrid Flow | |
---|---|---|---|
所有的tokens都來自於授權端點 | no | yes | no |
所有的tokens都來自於Token端點 | yes | no | no |
Tokens對瀏覽器隱藏 | yes | no | no |
客戶端可以被認證 | yes | no | yes |
可以使用Refresh Token | yes | no | yes |
只需一次往返通信 | no | yes | no |
大部分通信都是服務器對服務器 | yes | no | 看情況 |
返回類型值的比較:
"response_type" 的值 | Flow |
---|---|
code | Authorization Code Flow |
id_token | Implicit Flow |
id_token token | Implicit Flow |
code id_token | Hybrid Flow |
code token | Hybrid Flow |
code id_token token | Hybrid Flow |
本文就簡單介紹這些, OAuth 2.0 和 OpenID Connect 其余涉及到的內容會在后續Identity Server 4的系列文章里介紹.