認證授權:學習OIDC


 

前言

  上一篇文章介紹了OAuth2.0協議的相關內容,知道OAuth2.0是一個授權協議,無法提供完善的身份認證功能。那么什么來解決身份認證功能呢?——OIDC是一個不錯的解決方案。接下來進一步來了解OIDC是什么,有什么效果呢?

一、OIDC是什么

  OIDC是OpenID Connect 的簡稱,以下是OIDC官方的描述內容:

OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.

OpenID Connect allows clients of all types, including Web-based, mobile, and JavaScript clients, to request and receive information about authenticated sessions and end-users. The specification suite is extensible, allowing participants to use optional features such as encryption of identity data, discovery of OpenID Providers, and session management, when it makes sense for them.

  主要內容:OIDC是基於OAuth2.0協議的身份層,允許客戶端基於授權服務器執行的身份驗證來驗證最終用戶的身份,並以可互操作且類似於REST的方式獲取有關最終​​用戶的基本配置文件信息。並且支持所有客戶端類型(如基於Web的客戶端,移動客戶端和JavaScript客戶端)請求並接收有關經過身份驗證的會話和最終用戶的信息

二、OIDC相關的協議

  OIDC本身是有多個規范構成,其中最主要的是一個核心的規范,多個可選支持的規范來提供擴展支持

   主要包含:

   Core:必選。定義OIDC的核心功能,在OAuth 2.0之上構建身份認證,以及如何使用Claims來傳遞用戶的信息。
   Discovery:可選。發現服務,使客戶端可以動態的獲取OIDC服務相關的元數據描述信息
   Dynamic Client Registration:可選。動態注冊服務,使客戶端可以動態的注冊到OIDC的OP
   Session Management:可選。Session管理,用於規范OIDC服務如何管理Session信息
   Form Post Response Mode:可選。針對OAuth2的擴展,OAuth2回傳信息給客戶端是通過URL的querystring和fragment這兩種方式,這個擴展標准提供了一基於form表單的形式把數據post給客戶端的機制。
   基礎協議:
    OAuth2.0 Core:https://tools.ietf.org/html/rfc6749
    OAuth2.0 Bearer:https://tools.ietf.org/html/rfc6750
    OAuth2.0 Assertions:https://tools.ietf.org/html/rfc7521
    OAuth2.0 JWT Profile:https://tools.ietf.org/html/rfc7523
    OAuth2.0 Responses:可選。針對OAuth2的擴展,提供幾個新的response_type。
    JWT(JSON Web Token):https://tools.ietf.org/html/rfc7519
    JWS(JSON Web Signature):https://tools.ietf.org/html/rfc7515
    JWE(JSON Web Encryption):https://tools.ietf.org/html/rfc7516
    JWK(JSON Web Key):https://tools.ietf.org/html/rfc7517
    JWA(JSON Web Algorithms):https://tools.ietf.org/html/rfc7518
    WebFinger:https://tools.ietf.org/html/rfc7033

  

 

  上圖是官方給出的一個OIDC組成結構圖,可以看出OIDC不是什么新技術,它主要是借鑒OpenId的身份標識,OAuth2的授權和JWT包裝數據的方式,組合使用這些技術就是現在的OIDC。

  接下來就來學習里面最核心的相關內容(Core核心規范)。

 三、OIDC核心規范

  1、主要術語

    主要的術語以及概念介紹

    • EU:End User:最終用戶。
    • RP:Relying Party ,用來代指OAuth2中的受信任的客戶端,身份認證和授權信息的消費方;
    • OP:OpenID Provider,有能力提供EU認證的服務(比如OAuth2中的授權服務),用來為RP提供EU的身份認證信息;
    • ID Token:JWT格式的數據,包含EU身份認證的信息。
    • UserInfo Endpoint:用戶信息接口(受OAuth2保護),當RP使用Access Token訪問時,返回授權用戶的信息,此接口必須使用HTTPS。

  2、主要流程

    抽象的看主要包含以下步驟: 

    1. RP(客戶端)將請求發送到OpenID提供程序(OP)。
    2. OP驗證最終用戶並獲得授權。
    3. OP用ID Token(通常是訪問令牌)進行響應。
    4. RP可以將帶有訪問令牌(Access Token)的請求發送到UserInfo EndPoint。
    5. UserInfo端點返回有關最終用戶(EU)的聲明(Claims)。 

    

   上圖取自Core規范文檔,其中AuthN=Authentication,表示認證;AuthZ=Authorization,代表授權。注意這里面RP發往OP的請求,是屬於Authentication類型的請求,雖然在OIDC中是復用OAuth2的Authorization請求通道,但是用途是不一樣的,且OIDC的AuthN請求中scope參數必須要有一個值為的openid的參數(后面會詳細介紹AuthN請求所需的參數),用來區分這是一個OIDC的Authentication請求,而不是OAuth2的Authorization請求。 

   3、ID Token

    ID Token是OpenID Connect對OAuth 2.0進行的主要擴展(用於使最終用戶能夠通過身份驗證),ID Token是一種安全令牌,其中包含有關使用客戶端時授權服務器對最終用戶的身份驗證的聲明(Claims)以及可能的其他請求的聲明(Claims)的JWT格式數據。

    ID Token的主要構成部分如下:

    

名稱 完整名稱 是否必須 描述
iss Issuer Identifier 提供認證信息者的唯一標識。一般是一個https的url(不包含querystring和fragment部分)
sub Subject Identifier iss提供的EU的標識,在iss范圍內唯一。它會被RP用來標識唯一的用戶。最長為255個ASCII個字符。
aud Audience(s) 標識ID Token的受眾。必須包含OAuth2的client_id
exp Expiration time 過期時間,超過此時間的ID Token會作廢不再被驗證通過。
iat Issued At Time JWT的構建的時間
nonce   RP發送請求的時候提供的隨機字符串,用來減緩重放攻擊,也可以來關聯ID Token和RP本身的Session信息。
auth_time AuthenticationTime / EU完成認證的時間。如果RP發送AuthN請求的時候攜帶max_age的參數,則此Claim是必須的
acr Authentication Context Class Reference 表示一個認證上下文引用值,可以用來標識認證上下文類
amr Authentication Methods References 表示一組認證方法
azp  Authorized party 結合aud使用。只有在被認證的一方和受眾(aud)不一致時才使用此值,一般情況下很少使用

   一般情況在ID Token中還會包含其他聲明(Claims)內容,如用戶姓名、頭像等信息。OIDC提供了一組公共的cliams,可以到這里查看。另外ID Token必須使用JWS進行簽名和JWE加密,從而提供認證的完整性、不可否認性以及可選的保密性。

   例如:

  {
   "iss": "https://server.example.com",
   "sub": "24400320",
   "aud": "s6BhdRkqt3",
   "nonce": "n-0S6_WzA2Mj",
   "exp": 1311281970,
   "iat": 1311280970,
   "auth_time": 1311280969,
   "acr": "urn:mace:incommon:iap:silver"
  }

  4、認證

   了解了ID Token后,接下來就來看OIDC如何獲取ID Token的,由於OIDC基於OAuth2,所以OIDC的認證流程主要是由OAuth2的幾種授權流程延伸而來的,

   有以下3種

    • Authorization Code Flow:使用OAuth2的授權碼來換取Id Token和Access Token。
    • Implicit Flow:使用OAuth2的Implicit流程獲取Id Token和Access Token。
    • Hybrid Flow:混合Authorization Code Flow+Implici Flow。

OAuth2中還有基於Resource Owner Password Credentials Grant和Client Credentials Grant的方式來獲取Access Token,為什么OIDC沒有擴展這些方式呢?

Resource Owner Password Credentials Grant是需要用戶提供賬號密碼給RP的,賬號密碼給到RP,還需要什么ID Token

Client Credentials Grant這種方式根本就不需要用戶參與,更談不上用戶身份認證。這也能反映授權和認證的差異,以及只使用OAuth2來做身份認證的事情是遠遠不夠的,也是不合適的。

   4.1 授權碼流程(Authorization Code Flow)

授權碼流程執行以下步驟。 

    1. 客戶端准備一個包含所需請求參數的身份驗證請求。
    2. 客戶端將請求發送到授權服務器。
    3. 授權服務器對最終用戶進行身份驗證。
    4. 授權服務器獲得最終用戶同意/授權。
    5. 授權服務器使用授權碼將最終用戶發送回客戶端。
    6. 客戶端使用令牌端點上的授權碼來請求響應。
    7. 客戶端收到響應,該響應在響應主體中包含ID令牌和訪問令牌。
    8. 客戶端驗證ID令牌並檢索最終用戶的主題標識符。

    4.1.1 認證請求

      該方式使用OAuth2的Authorization Code的方式來完成用戶身份認證,所有的Token都是通過Token EndPoint來發放的。構建一個OIDC的Authentication Request需要提供如下的參數:

參數 必須 說明
scope OIDC的請求必須包含值為“openid”的scope的參數
response_type 同OAuth2
client_id 同OAuth2
redirect_uri 同OAuth2
state 推薦 同OAuth2,防止CSRF, XSRF
response_mode OIDC新定義的參數(OAuth 2.0 Form Post Response Mode),用來指定Authorization Endpoint以何種方式返回數據
nonce ID Token中的出現的nonce就是來源於此
display 指示授權服務器呈現怎樣的界面給EU。有效值有(page,popup,touch,wap),其中默認是page。page=普通的頁面,popup=彈出框,touch=支持觸控的頁面,wap=移動端頁面。
prompt 這個參數允許傳遞多個值,使用空格分隔。用來指示授權服務器是否引導EU重新認證和同意授權(consent,就是EU完成身份認證后的確認同意授權的頁面)。有效值有(none,login,consent,select_account)。none=不實現現任何認證和確認同意授權的頁面,如果沒有認證授權過,則返回錯誤login_required或interaction_required。login=重新引導EU進行身份認證,即使已經登錄。consent=重新引導EU確認同意授權。select_account=假如EU在授權服務器有多個賬號的話,允許EU選擇一個賬號進行認證。
max_age 代表EU認證信息的有效時間,對應ID Token中auth_time的claim。比如設定是20分鍾,則超過了時間,則需要引導EU重新認證
ui_locales 用戶界面的本地化語言設置項
id_token_hint 之前發放的ID Token,如果ID Token經過驗證且是有效的,則需要返回一個正常的響應;如果有誤,則返回對應的錯誤提示
login_hint 向授權服務器提示登錄標識符,EU可能會使用它登錄(如果需要的話)。比如指定使用用戶使用blackheart賬號登錄,當然EU也可以使用其他賬號登錄,這只是類似html中input元素的placeholder。
acr_values Authentication Context Class Reference values,對應ID Token中的acr的Claim。此參數允許多個值出現,使用空格分割

      以上是基於Authorization Code方式的OIDC的認證請求所需的參數。在OIDC的其他認證流程中也會有其他的參數或不同的參數值(稍有差異)示例如下:

  GET /authorize?
    response_type=code
    &scope=openid%20profile%20email
    &client_id=s6BhdRkqt3
    &state=af0ifjsldkj
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
  Host: server.example.com

    4.1.2 認證請求的響應

      授權服務器接收到請求后,進行了:OAuth2.0參數驗證、scope參數是否包含openid的范圍值、授權服務器必須參數是否存等相關驗證(詳見);驗證通過后引導EU進行身份認證並同意授權。然后會重定向到RP指定的回調地址,並且把code和state參數傳遞過去:如下:

 HTTP/1.1 302 Found
  Location: https://client.example.org/cb?
    code=SplxlOBeZQQYbYS6WxSbIA
    &state=af0ifjsldkj

     4.1.3 獲取IDToken

      接下來PR會根據獲取的Code來請求Token EndPoint,和OAuth2.0請求相同;Token EndPoint接收到請求后會返回相應的Token,除了OAuth2規定的部分數據外,還會附加一個id_token的字段。id_token字段就是上面提到的ID Token。示例如下:

  HTTP/1.1 200 OK
  Content-Type: application/json
  Cache-Control: no-store
  Pragma: no-cache

  {
   "access_token": "SlAV32hkKG",
   "token_type": "Bearer",
   "refresh_token": "8xLOxBtZp8",
   "expires_in": 3600,
   "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
     yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
     NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
     fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
     AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
     Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
     NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
     QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
     K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
     XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"
  }

  4.2 隱式流(Implicit Flow)

隱式流遵循以下步驟: 

    1. 客戶端准備一個包含所需請求參數的身份驗證請求。
    2. 客戶端將請求發送到授權服務器。
    3. 授權服務器對最終用戶進行身份驗證。
    4. 授權服務器獲得最終用戶同意/授權。
    5. 授權服務器使用ID令牌和訪問令牌(如果要求)將最終用戶發送回客戶端。
    6. 客戶端驗證ID令牌並檢索最終用戶的主題標識符。   

   4.2.1 認證請求

     按照4.1.1定義進行身份驗證請求,不同的是,這些身份驗證請求參數的使用方式如下:

    • response_type值換成id_token token 或 id_token

     示例如下:      

  GET /authorize?
    response_type=id_token%20token
    &client_id=s6BhdRkqt3
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
    &scope=openid%20profile
    &state=af0ifjsldkj
    &nonce=n-0S6_WzA2Mj HTTP/1.1
  Host: server.example.com

   4.2.1 認證請求響應

     響應結果如下:

  HTTP/1.1 302 Found
  Location: https://client.example.org/cb#
    access_token=SlAV32hkKG
    &token_type=bearer
    &id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso
    &expires_in=3600
    &state=af0ifjsldkj

  4.3 混合流(Hybrid Flow)

混合流遵循以下步驟: 

    1. 客戶端准備一個包含所需請求參數的身份驗證請求。
    2. 客戶端將請求發送到授權服務器。
    3. 授權服務器對最終用戶進行身份驗證。
    4. 授權服務器獲得最終用戶同意/授權。
    5. 授權服務器使用授權碼以及一個或多個其他參數(根據響應類型)將最終用戶發送回客戶端。
    6. 客戶端使用令牌端點上的授權碼來請求響應。
    7. 客戶端收到響應,該響應在響應主體中包含ID令牌和訪問令牌。
    8. 客戶端驗證ID令牌並檢索最終用戶的主題標識符。

   4.3.1 認證請求

     按照4.1.1定義進行身份驗證請求,不同的是,這些身份驗證請求參數的使用方式如下:

    • response_type值換成:code id_tokencode token, or code id_token token.
  GET /authorize?
    response_type=code%20id_token
    &client_id=s6BhdRkqt3
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
    &scope=openid%20profile%20email
    &nonce=n-0S6_WzA2Mj
    &state=af0ifjsldkj HTTP/1.1
  Host: server.example.com

   4.3.1 認證請求響應

    以下是使用“混合流”成功響應

  HTTP/1.1 302 Found
  Location: https://client.example.org/cb#
    code=SplxlOBeZQQYbYS6WxSbIA
    &id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso
    &state=af0ifjsldkj

總結:

   OIDC的好處:

    • OIDC使得身份認證可以作為一個服務存在

    • OIDC可以很方便的實現SSO(跨頂級域)

    • OIDC兼容OAuth2,可以使用Access Token控制受保護的API資源
    • OIDC可以兼容眾多的IDP(身份提供商)作為OIDC的OP來使用

    • OIDC的一些敏感接口均強制要求TLS,除此之外,得益於JWT,JWS,JWE家族的安全機制,使得一些敏感信息可以進行數字簽名、加密和驗證,進一步確保整個認證過程中的安全保障

參考

官方資料:

http://openid.net/connect/

http://openid.net/connect/faq/

http://openid.net/developers/certified/

案例:https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-openid-connect-code

參考引用:https://www.cnblogs.com/linianhui/p/openid-connect-core.html

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM