Identity Server 4 預備知識 -- OpenID Connect 簡介

solenovex發表於2018-06-27

我之前的文章簡單的介紹了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流程的步驟如下:

  1. 客戶端準備身份認證請求, 請求裡包含所需的引數
  2. 客戶端傳送請求到授權伺服器
  3. 授權伺服器對終端使用者進行身份認證
  4. 授權伺服器獲得終端使用者的同意/授權
  5. 授權伺服器把終端使用者傳送回客戶端, 同時帶著授權碼
  6. 客戶端使用授權碼向Token端點請求一個響應
  7. 客戶端接收到響應, 響應的body裡面包含著ID Token 和 Access Token
  8. 客戶端驗證ID Token, 並獲得使用者的一些身份資訊.

 

Implicit Flow

Implicit流程在請求token的時候不需要明確的客戶端身份認證, 它使用重定向URI的方式來驗證客戶端的身份. 因為這一點, refresh token也就無法使用了, 這同樣也不適合於長時間有效的access token.

在Implicit流程裡, 所有的tokens都來自於授權端點, 而Token端點並沒有用到.

該流程主要用於瀏覽器內的應用, Access Token和ID Token一同被直接返回給客戶端. 因為這個原因, 這些tokens也會暴露於終端使用者和可以訪問該瀏覽器的其它應用了. 

它並不適合於長時間的訪問.

Implicit流程的步驟如下:

  1. 客戶端準備身份認證請求, 請求裡包含所需的引數
  2. 客戶端傳送請求到授權伺服器
  3. 授權伺服器對終端使用者進行身份認證
  4. 授權伺服器獲得終端使用者的同意/授權
  5. 授權伺服器把終端使用者傳送回客戶端, 同時帶著ID Token. 如果也請求了Access Token的話, 那麼Access Token也會一同返回.
  6. 客戶端驗證ID Token, 並獲得使用者的一些身份資訊.

 

Hybrid Flow

Hybrid流程是前兩者的混合, 在該流程裡, 有一些tokens和授權碼來自於授權端點, 而另外一些tokens則來自於Token端點.

該流程允許客戶端立即使用ID Token, 並且只需要一次往返即可獲得授權碼.

這種流程也要求客戶端應用可以安全的維護secret.

它也適合於長時間的訪問.

Hybrid流程的步驟如下:

  1. 客戶端準備身份認證請求, 請求裡包含所需的引數
  2. 客戶端傳送請求到授權伺服器
  3. 授權伺服器對終端使用者進行身份認證
  4. 授權伺服器獲得終端使用者的同意/授權
  5. 授權伺服器把終端使用者傳送回客戶端, 同時帶著授權碼, 根據響應型別的不同, 也可能還帶著一個或者多個其它的引數.
  6. 客戶端使用授權碼向Token端點請求一個響應
  7. 客戶端接收到響應, 響應的body裡面包含著ID Token 和 Access Token
  8. 客戶端驗證ID Token, 並獲得使用者的一些身份資訊.

 

三種流程特點的比較:

 Authorization Code FlowImplicit FlowHybrid 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的系列文章裡介紹.

相關文章