OpenID Connect 協(xié)議入門指南

如果要談單點登錄和身份認證,就不得不談OpenID Connect (OIDC)。最典型的使用實例就是使用Google賬戶登錄其他應用,這一經(jīng)典的協(xié)議模式,為其他廠商的第三方登錄起到了標桿的作用,被廣泛參考和使用。

相關閱讀:
OAuth2.0 協(xié)議入門指南
SAML2.0入門指南

1. OpenID Connect簡介

OpenID Connect是基于OAuth 2.0規(guī)范族的可互操作的身份驗證協(xié)議。它使用簡單的REST / JSON消息流來實現(xiàn),和之前任何一種身份認證協(xié)議相比,開發(fā)者可以輕松集成。

OpenID Connect允許開發(fā)者驗證跨網(wǎng)站和應用的用戶,而無需擁有和管理密碼文件。OpenID Connect允許所有類型的客戶,包括基于瀏覽器的JavaScript和本機移動應用程序,啟動登錄流動和接收可驗證斷言對登錄用戶的身份。

2. OpenID的歷史是什么?

OpenID Connect是OpenID的第三代技術。首先是原始的OpenID,它不是商業(yè)應用,但讓行業(yè)領導者思考什么是可能的。OpenID 2.0設計更為完善,提供良好的安全性保證。然而,其自身存在一些設計上的局限性,最致命的是其中依賴方必須是網(wǎng)頁,但不能是本機應用程序;此外它還要依賴XML,這些都會導致一些應用問題。

OpenID Connect的目標是讓更多的開發(fā)者使用,并擴大其使用范圍。幸運的是,這個目標并不遙遠,現(xiàn)在有很好的商業(yè)和開源庫來幫助實現(xiàn)身份驗證機制。

3. OIDC基礎

簡要而言,OIDC是一種安全機制,用于應用連接到身份認證服務器(Identity Service)獲取用戶信息,并將這些信息以安全可靠的方法返回給應用。

在最初,因為OpenID1/2經(jīng)常和OAuth協(xié)議(一種授權協(xié)議)一起提及,所以二者經(jīng)常被搞混。

  • OpenIDAuthentication,即認證,對用戶的身份進行認證,判斷其身份是否有效,也就是讓網(wǎng)站知道“你是你所聲稱的那個用戶”;
  • OAuthAuthorization,即授權,在已知用戶身份合法的情況下,經(jīng)用戶授權來允許某些操作,也就是讓網(wǎng)站知道“你能被允許做那些事情”。
    由此可知,授權要在認證之后進行,只有確定用戶身份只有才能授權。

(身份驗證)+ OAuth 2.0 = OpenID Connect

OpenID Connect是“認證”和“授權”的結合,因為其基于OAuth協(xié)議,所以OpenID-Connect協(xié)議中也包含了client_idclient_secret還有redirect_uri等字段標識。這些信息被保存在“身份認證服務器”,以確保特定的客戶端收到的信息只來自于合法的應用平臺。這樣做是目的是為了防止client_id泄露而造成的惡意網(wǎng)站發(fā)起的OIDC流程。

舉個例子。某個用戶使用Facebook應用“What online quiz best describes you?” ,該應用可以通過Facebook賬號登錄,則你可以在應用中發(fā)起請求到“身份認證服務器”(也就是Facebook的服務器)請求登錄。這時你會看到如下界面,詢問是否授權。

image.png

OAuth中,這些授權被稱為scopeOpenID-Connect也有自己特殊的scope--openid ,它必須在第一次請求“身份鑒別服務器”(Identity Provider,簡稱IDP)時發(fā)送過去。

4. OIDC流程

OAuth2提供了Access Token來解決授權第三方客戶端訪問受保護資源的問題;相似的,OIDC在這個基礎上提供了ID Token來解決第三方客戶端標識用戶身份認證的問題。OIDC的核心在于在OAuth2的授權流程中,一并提供用戶的身份認證信息(ID-Token)給到第三方客戶端,ID-Token使用JWT格式來包裝,得益于JWTJSON Web Token)的自包含性,緊湊性以及防篡改機制,使得ID-Token可以安全的傳遞給第三方客戶端程序并且容易被驗證。應有服務器,在驗證ID-Token正確只有,使用Access-TokenUserInfo的接口換取用戶的更多的信息。

有上述可知,OIDC是遵循OAuth協(xié)議流程,在申請Access-Token的同時,也返回了ID-Token來驗證用戶身份。

4.1 相關定義

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

下面我們來看看OIDC的具體協(xié)議流程。
根據(jù)應用客戶端的不同,OIDC的工作模式也應該是不同的。和OAuth類似,主要看是否客戶端能保證client_secret的安全性。

如果是JS應用,其所有的代碼都會被加載到瀏覽器而暴露出來,沒有后端可以保證client_secret的安全性,則需要是使用默認模式流程(Implicit Flow)。

如果是傳統(tǒng)的客戶端應用,后端代碼和用戶是隔離的,能保證client_secret的不被泄露,就可以使用授權碼模式流程(Authentication Flow)。

此外還有混合模式流程(Hybrid Flow),簡而言之就是以上二者的融合。

OAuth2中還有口令模式和“應有訪問模式”的方式來獲取Access Token(關于OAuth2的內(nèi)容,可以參見OAuth2.0 協(xié)議入門指南),為什么OIDC沒有擴展這些方式呢?
"口令模式"是需要用戶提供賬號和口令給RP的,既然都已經(jīng)有用戶名和口令了,就不需要在獲取什么用戶身份了。至于“應有訪問模式”,這種方式不需要用戶參與,也就無需要認證和獲取用戶身份了。這也能反映授權和認證的差異,以及只使用OAuth2來做身份認證的事情是遠遠不夠的,也是不合適的。

4.2 授權碼模式流程

授權碼模式流程

OAuth認證流程類似

  1. RP發(fā)送一個認證請求給OP,其中附帶client_id
  2. OP對EU進行身份認證;
  3. OP返回響應,發(fā)送授權碼給RP;
  4. RP使用授權碼向OP索要ID-Token和Access-Token,RP驗證無誤后返回給RP;
  5. RP使用Access-Token發(fā)送一個請求到UserInfo EndPoint; UserInfo EndPoint返回EU的Claims。

4.2.1 基于Authorization Code的認證請求

RP使用OAuth2的Authorization-Code的方式來完成用戶身份認證,所有的Token都是通過OP的Token EndPoint(OAuth2中定義)來發(fā)放的。構建一個OIDC的Authentication Request需要提供如下的參數(shù):

  • scope:必須。OIDC的請求必須包含值為“openid”的scope的參數(shù)。
  • response_type:必選。同OAuth2。
  • client_id:必選。同OAuth2。
  • redirect_uri:必選。同OAuth2。
  • state:推薦。同OAuth2。防止CSRF, XSRF。

示例如下:

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.2.2 基于Authorization Code的認證請求的響應

在OP接收到認證請求之后,需要對請求參數(shù)做嚴格的驗證,具體的規(guī)則參見http://openid.net/specs/openid-connect-core-1_0.html#AuthRequestValidation,驗證通過后引導EU進行身份認證并且同意授權。在這一切都完成后,會重定向到RP指定的回調(diào)地址(redirect_uri),并且把codestate參數(shù)傳遞過去。比如:

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

4.2.3 獲取ID Token

RP使用上一步獲得的code來請求Token EndPoint,這一步桶OAuth2,就不再展開細說了。然后Token EndPoint會返回響應的Token,其中除了OAuth2規(guī)定的部分數(shù)據(jù)外,還會附加一個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"
  }

其中看起來一堆亂碼的部分就是JWT格式的ID-Token。在RP拿到這些信息之后,需要對id_token以及access_token進行驗證(具體的規(guī)則參見http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidationhttp://openid.net/specs/openid-connect-core-1_0.html#ImplicitTokenValidation)。至此,可以說用戶身份認證就可以完成了,后續(xù)可以根據(jù)UserInfo EndPoint獲取更完整的信息。

4.2.4 安全令牌 ID-Token

上面提到過OIDCOAuth2最主要的擴展就是提供了ID-Token。下面我們就來看看ID-Token的主要構成:

  • iss = Issuer Identifier:必須。提供認證信息者的唯一標識。一般是Url的host+path部分;
  • sub = Subject Identifier:必須。iss提供的EU的唯一標識;最長為255個ASCII個字符;
  • aud = Audience(s):必須。標識ID-Token的受眾。必須包含OAuth2的client_id;
  • exp = Expiration time:必須。ID-Token的過期時間;
  • iat = Issued At Time:必須。JWT的構建的時間。
  • auth_time = AuthenticationTime:EU完成認證的時間。如果RP發(fā)送認證請求的時候攜帶max_age的參數(shù),則此Claim是必須的。
  • nonce:RP發(fā)送請求的時候提供的隨機字符串,用來減緩重放攻擊,也可以來關聯(lián)ID-Token和RP本身的Session信息。
  • acr = Authentication Context Class Reference:可選。表示一個認證上下文引用值,可以用來標識認證上下文類。
  • amr = Authentication Methods References:可選。表示一組認證方法。
  • azp = Authorized party:可選。結合aud使用。只有在被認證的一方和受眾(aud)不一致時才使用此值,一般情況下很少使用。
{
   "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"
  }

另外ID Token必須使用JWT(JSON Web Token)進行簽名和JWE(JSON Web Encryption)加密,從而提供認證的完整性、不可否認性以及可選的保密性。關于JWT的更多內(nèi)容,請參看JSON Web Token - 在Web應用間安全地傳遞信息

4.2 默認模式流程

默認模式流程

默認流程和OAuth中的類似,只不過也是添加了ID-Token的相關內(nèi)容。

這里需要說明的是:OIDC的說明文檔里很明確的說明了用戶的相關信息都要使用JWT形式編碼。在JWT中,不應該在載荷里面加入任何敏感的數(shù)據(jù)。如果傳輸?shù)氖怯脩舻腢ser ID。這個值實際上不是什么敏感內(nèi)容,一般情況下被知道也是安全的。

但是現(xiàn)在工業(yè)界已經(jīng)不推薦使用OAuth默認模式,而推薦使用不帶client_Secret授權碼模式

4.3 混合模式

混合模式簡而言之就是以上提到的兩種模式的混合,不過也有一些小的改變,就是允許直接向客戶端返回Access-Token

業(yè)界普遍認為,后端傳遞Token(比如服務器之間通信)要比前端(比如頁面之間)可靠,所以如果直接返回令牌的情況下會把令牌的過期時間設置較短,但是比較

UserInfo Endpoint

可能有的讀者發(fā)現(xiàn)了,ID-Token只有sub是和EU相關的,這在一般情況下是不夠的,必須還需要EU的用戶名,頭像等其他的資料,OIDC提供了一組公共的cliams,來提供更多用戶的信息,這就是——UserIndo EndPoin。

在RP得到Access Token后可以請求此資源,然后獲得一組EU相關的Claims,這些信息可以說是ID-Token的擴展,ID-Token中只需包含EU的唯一標識sub即可(避免ID Token過于龐大和暴露用戶敏感信息),然后在通過此接口獲取完整的EU的信息。此資源必須部署在TLS之上,例如:

  GET /userinfo HTTP/1.1
  Host: server.example.com
  Authorization: Bearer SlAV32hkKG

成功之后響應如下:

  HTTP/1.1 200 OK
  Content-Type: application/json

  {
   "sub": "248289761001",
   "name": "Jane Doe",
   "given_name": "Jane",
   "family_name": "Doe",
   "preferred_username": "j.doe",
   "email": "janedoe@example.com",
   "picture": "http://example.com/janedoe/me.jpg"
  }

其中sub代表EU的唯一標識,這個claim是必須的,其他的都是可選的。

參考文獻

更多關于OIDC的內(nèi)容,請閱讀以下文章:

  1. https://www.onelogin.com/blog/openid-connect-explained-in-plain-english
  2. http://www.cnblogs.com/linianhui/archive/2017/05/30/openid-connect-core.html
  3. JSON Web Token - 在Web應用間安全地傳遞信息
  4. OAuth2.0 協(xié)議入門指南
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,247評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,520評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,362評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,805評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,541評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,896評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,887評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,062評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,608評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,356評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,555評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,077評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,769評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,175評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,489評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,289評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,516評論 2 379

推薦閱讀更多精彩內(nèi)容