認(rèn)證(authenticate)和授權(quán)(authorize)是倆個容易被弄混的概念,尤其是只看英文。
認(rèn)證意味著證實某個用戶是他所聲明的那個人;授權(quán)意味決定一個身份確定的用戶能夠訪問哪些資源。
認(rèn)證授權(quán)是目前大多數(shù)系統(tǒng)都必須要實現(xiàn)的功能,認(rèn)證就是驗證用戶的身份,授權(quán)就是驗證身份后對受限資源的訪問控制。最開始是單個平臺要做,后來在互聯(lián)網(wǎng)時代到來,一個賬戶可登陸多個平臺,然后是各種開放平臺賬戶共享,認(rèn)證授權(quán)變得越來越重要。關(guān)于驗證授權(quán)方面的規(guī)范協(xié)議也相對成熟通用。
單店登錄和統(tǒng)一認(rèn)證中主要三個協(xié)議是OpenID、OAuth和SAML被稱為單點登錄的三駕馬車。
最早出現(xiàn)的認(rèn)證授權(quán)協(xié)議是SMAL,一般用在企業(yè)級單點登錄場景。平時接觸到的不多。
OAuth是看到的用的比較多的認(rèn)證協(xié)議,尤其是在API認(rèn)證授權(quán)時用,最開始是1.0版本,后來因為有會話共計、會話劫持的漏洞,除了1.0a版本,但編程實現(xiàn)較麻煩,后來出現(xiàn)OAuth2版本,但不兼容之前的版本。一般見到大多數(shù)時用的是OAuth2.
OpenId一開始出現(xiàn)是為了解決認(rèn)證的問題,后來出現(xiàn)了OpenId Connect,在OAuth的基礎(chǔ)上也可以實現(xiàn)授權(quán)的功能。
| 對比點 | OAuth2 | OpenId | SMAL |
|---|---|---|---|
| 票據(jù)格式 | JSON or SAML2 | JSON | XML |
| 支持授權(quán) | Yes | No | Yes |
| 支持認(rèn)證 | 偽認(rèn)證 | Yes | Yes |
| 創(chuàng)建年份 | 2005 | 2006 | 2001 |
| 最新版本 | OAuth2 | OpenID Connect | SAML2.0 |
| 傳輸方式 | HTTP | HTTP GET and HTTP POST | HTTP重定向,SAML SOAP綁定 ,HTTP POST綁定 |
| 安全弱點 | 不能抵抗網(wǎng)絡(luò)釣魚,OAyth沒有使用數(shù)據(jù)簽名和加密等措施,數(shù)據(jù)安全完全依賴TLS | 不能抵抗網(wǎng)絡(luò)釣魚,一個釣魚的IDP如果惡意記錄下來用戶的OpenID,將會造成很嚴(yán)重的隱私安全問題。 | XML簽名存在漏洞,可能被偽造。 |
| 使用場景 | API授權(quán) | 商用應(yīng)用的單店登錄 | 企業(yè)級的單店登錄,但是對于移動端支持不是很好。 |
SAML2.0協(xié)議
SAML,全稱為Security Assertion Markup Language,是一種用于安全性斷言的標(biāo)記語言,目前最新版本是2.0。
SAML在單點登錄中大有用處:在SAML協(xié)議中,一旦用戶身份被主網(wǎng)站(身份鑒別服務(wù)器,Identity Provider,IDP)認(rèn)證過后,該用戶再去范文其他在主網(wǎng)站注冊過的應(yīng)用(服務(wù)提供者,Service Providers,SP)時,都可以直接登錄,而不用在輸入身份和口令。
SAML協(xié)議的核心是:IDP和SP通過用戶的瀏覽器的重定向訪問來實現(xiàn)交換數(shù)據(jù)。
SP向IDP發(fā)出SAML身份認(rèn)證請求消息,來請求IDP鑒別用戶身份;IDP向用戶索要用戶名和口令,并驗證其是否正確,如果驗證無誤,則想SP返回SAML身份認(rèn)證應(yīng)答,表示該用戶已經(jīng)登錄成功了,此外應(yīng)答中還包括一些額外的信息,來確保應(yīng)答不被篡改和偽造。
下面我們以用戶登錄SP,SP向IDP發(fā)起求情來確認(rèn)用戶身份微粒子,看看SAML的工作流程。比如SP是Google的Apps,IDP是一所大學(xué)的身份服務(wù)器,Alice是該大學(xué)的一名學(xué)生。

現(xiàn)在Alice要通過瀏覽器查閱她的郵件,Alice一般會通過瀏覽器訪問一個網(wǎng)頁,比如https://mail.google.com/a/my-university.nl.因為這是個聯(lián)合身份域,所以Google不會向用戶索取用戶名和密碼,而是將其重定向到IDP來認(rèn)證其身份。用戶被重定向的URL類似于這種:
https://idp:uni.nl/sso?SAMLRequest=fVLLTuswEN0j8Q...C%3D
嵌入到HTTP請求中的SAMLRequest就是SAML認(rèn)證請求消息。因為SAML是基于XML的(通常比較長),完整認(rèn)證求情消息要經(jīng)過壓縮(為Url節(jié)省空間)和編碼(防止特殊字符)才能傳輸。在壓縮和編碼之前,SAML消息有如下格式:
<AuthnRequest ID="kfcn...lfki"
Version="2.0"
IssueInstant="2013-02-05T08:28:50Z"
ProtocolBinding="urn:oasis:names:tc:SAML: 2.0:bindings:HTTP-POST"
ProviderName="google.com"
AssertionConsumerServiceURL="https://www.google.com/a/uni.nl/acs">
<Issuer>google.com</Issuer>
<NameIDPolicy AllowCreate="true"
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"/>;
</AuthnRequest>;
上面的內(nèi)容用最直白的方式解釋出來就是:這個來自Google的求情,請驗證當(dāng)前用戶身份,并將結(jié)果返回
當(dāng)IDP收到消息并確認(rèn)要接受認(rèn)證求情之后,就會要求Alice輸入用戶名和口令來驗證其身份(如果Alice已經(jīng)登陸過了,就會跳過該步驟);當(dāng)驗證通過之后,Alice的瀏覽器將會跳轉(zhuǎn)回google的特定頁面(AssertionConsumerService 簡稱ACS)。同樣,SAML身份認(rèn)證響應(yīng)的內(nèi)容也是在壓縮并編碼后以參數(shù)形式傳輸。在壓縮和編碼之前,其結(jié)構(gòu)如下:
<Response Version="2.0"
IssueInstant="2013-02-05T08:29:00Z"
Destination="https://www.google.com/a/my.uni.nl/acs" InResponseTo="kfcn...lfki">
<Issuer>https://idp.uni.nl/</Issuer>
<Status>
<StatusCode
Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</Status>
<Assertion Version="2.0"
IssueInstant="2013-02-05T08:29:00Z">
<Issuer>https://idp.uni.nl/</Issuer>
<Subject>
<NameID>alice</NameID>
<SubjectConfirmation ...>
<SubjectConfirmationData
NotOnOrAfter="2013-02-05T08:34:00Z"
Recipient="https://www.google.com/a/my.uni.nl/acs" InResponseTo="kfcn...lfki"/>
</SubjectConfirmation>
</Subject>
<Conditions NotBefore="2013-02-05T08:28:30Z" NotOnOrAfter="2013-02-05T08:34:00Z">
</Conditions>
<AuthnStatement
AuthnInstant="2013-02-05T08:29:00Z"
SessionNotOnOrAfter="2013-02-05T16:29:00Z>
</AuthnStatement>
</Assertion>
</Response>
雖然內(nèi)容很多,但是其主要表達(dá)的是:該消息來自idp.uni.nl,名為Alice的用戶身份已經(jīng)被我驗證,該消息的有效期分2分鐘,此外重定向的URL中還要有該消息的簽名以保證其不被篡改,驗證簽名的公鑰和算法,都是IDP和SP提前協(xié)商好的。
當(dāng)Google接受到SAML認(rèn)證相應(yīng)之后,會首先驗證消息的簽名是否正確以及是否超時失效,然后再從認(rèn)證消息中提取出Google能識別用戶身份(NameId 即Alice)如果以上的步驟都是順利的,用戶將會成功登陸Google。
為了便于解釋,以上例子中的信息都保持可讀性,如果想要去看看真實的SAML信息,建議使用火狐瀏覽器的插件工具SAML tracer。該插件將會在瀏覽器中添加一個窗口來顯示SAML消息,一下是截圖。

參考
http://www.itdecent.cn/p/636c1ee16eba
OAuth2.0協(xié)議
協(xié)議中的各種角色:應(yīng)用、API和用戶
- 第三方應(yīng)用:客戶端。即嘗試去獲得用戶賬戶信息的應(yīng)用,用戶需要先對此操作授權(quán)。
- API:資源服務(wù)器,提供用來獲得用戶信息的API。
- 授權(quán)服務(wù)器:讓用戶同意或者拒絕訪問請求。在某些情況下,授權(quán)服務(wù)器和API資源服務(wù)器會是同一個,但是在大多數(shù)情況下,二者是獨立的。
- 用戶:資源的擁有者,當(dāng)前請求正在嘗試獲得他們賬戶的部分信息。
創(chuàng)建App
在開始OAuth流程之前,首先需要注冊一個新應(yīng)用到服務(wù)器。通常在注冊的過程中,需要提供應(yīng)用的基本信息,比如應(yīng)用名稱、網(wǎng)站信息、logo等等。此外,你還需要注冊一個重定向URI,用以將用戶通過瀏覽器或者移動客戶端重定向回Web服務(wù)器,這個URI很重要。
重定向URI
服務(wù)器只會把用戶重定向回注冊過的URI以避免有些安全攻擊。任何HTTP的重定向請求都必須會用TLS保護(hù),所以要求使用HTTPS。這樣的要求是為了防止token在傳輸過程中被截獲。對于原生APP,重定向的URI可以被注冊為一個自定義的URL scheme,比如:
demoapp://redirect
Client ID & Secret
當(dāng)注冊完畢之后,一般會返回給用戶一個客戶端ID(Client ID)和一個客戶端秘鑰(Client Secret)。這個ID一般是公開的信息,用來構(gòu)造登錄URL,或者被包含在頁面的JS代碼中。這個秘鑰必須是保密的。如果一個已經(jīng)部署的應(yīng)用不能保護(hù)秘鑰,比如一個簡單的JS網(wǎng)頁,則不應(yīng)該使用客戶端秘鑰,同時理論上服務(wù)器也不應(yīng)該向這類應(yīng)用頒發(fā)秘鑰。
授權(quán) 得到授權(quán)碼
OAuth2 流程的第一步是獲得用戶的授權(quán)。對于基于瀏覽器應(yīng)用或是移動應(yīng)用,這一步通常是在服務(wù)器顯示給用戶的接口上完成的。
OAuth2 提供了多種授權(quán)模式,根據(jù)不同情況而使用。
- 授權(quán)碼模式:適用于web應(yīng)用,瀏覽器應(yīng)用或是移動APP
- 口令模式:適用于使用用戶名和口令登錄的模式
- 應(yīng)用訪問模式:適用于應(yīng)用訪問
- 默認(rèn)模式:之前被推薦,在沒有Secret的情況下使用,現(xiàn)在被沒有客戶端秘鑰的授權(quán)碼模式取代
Web 服務(wù)
Web服務(wù)是最常見的應(yīng)用類型。用戶所使用的Web App程序運(yùn)行在服務(wù)器端,其源碼不會公開暴露,這就代表著這類應(yīng)用在授權(quán)的過程中可以使用客戶端秘鑰(Client Secret),以避免某些攻擊手段。
授權(quán)
創(chuàng)建登錄鏈接,將用戶重定向到授權(quán)服務(wù)器:
https://oauth2server.com/auth?response_type=code&
client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos&state=abcdef
- code:代表服務(wù)器希望收到授權(quán)碼
- client_id:注冊應(yīng)用時頒發(fā)的ID
- redirect_uri:指明當(dāng)用戶授權(quán)完成之后返回的地址;
- scope:一個或多個值,用來指明希望獲得用戶賬戶哪部分權(quán)限;
- state:由應(yīng)用生成的一個隨機(jī)字符串,會在之后的過程中去驗證。
通過以上鏈接,用戶將看到如下的界面

當(dāng)用戶點擊allow后,授權(quán)服務(wù)器會把用戶重定向回應(yīng)用網(wǎng)站,并在連接中帶上授權(quán)碼
https://oauth2client.com/cb?code=AUTH_CODE_HERE&state=abcdef
- code:IDP服務(wù)器返回的授權(quán)碼
- state:返回請求授權(quán)碼過程中發(fā)送的state
當(dāng)應(yīng)用有接收到這個請求時,要首先驗證state是否就是應(yīng)用剛才發(fā)送的值。在發(fā)送state之后,可以吧state保存到Session以便于后序的比較。這樣做的目的是防止應(yīng)用接受任意偽造的授權(quán)碼。
換取Token
然后使用授權(quán)碼到資源服務(wù)器換取Token
POST https://api.oauth2server.com/token
grant_type=authorization_code&
code=AUTH_CODE_HERE&
redirect_uri=REDIRECT_URI&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET
- grant_type = authorization_code :代表授權(quán)模式為授權(quán)碼模式
- code = AUTH_CODE_HERE:為上一步code中獲取的授權(quán)碼
- redirect_uri = REDIRECT_URI 重定向URI
- client_id = CLIENT_ID 注冊應(yīng)用時頒發(fā)的ID
- client_secret=CLIENT_SECRET 客戶端秘鑰,因為當(dāng)前請求是服務(wù)器之間的傳輸,并沒有暴露給用戶。
IDP服務(wù)器會返回授權(quán)碼和有效期:
{
"access_token":"RsT5OjbzRn430zqMLgV3Ia",
"expires_in":3600
}
或者是授權(quán)失敗的提示
{
"error":"invalid_request"
}
注意:服務(wù)器要求應(yīng)用必須提前注冊重定向的URI
口令模式
這種模式直接使用用戶名和密碼來取回token。很顯然,這種應(yīng)用去手機(jī)用戶的口令,所以之間以當(dāng)前的App是專門為服務(wù)器設(shè)計的情況下使用。
POST https://api.oauth2server.com/token
grant_type=password&
username=USERNAME&
password=PASSWORD&
client_id=CLIENT_ID
- grant_type=password 指明使用口令模式
- username=USERNAME 用戶名
- password=PASSWORD 口令
- client_id=CLIENT_ID client
資源服務(wù)器返回的Token和其他模式一樣。值得注意的是,因為口令模式多用于移動端和桌面應(yīng)用,使用secret并不合適。
應(yīng)用訪問模式
在一些情況下,是應(yīng)用去訪問服務(wù)器獲取資源。而不是某個用戶。比如應(yīng)用去獲取一些服務(wù)在應(yīng)用的配置信息,這些信息不屬于某個用戶的。這種情況下,應(yīng)用也需要被授權(quán),得到Token去訪問數(shù)據(jù),這就是應(yīng)用訪問模式的意義。
Oauth提供了Client_credentials模式來處理這個問題:
POST https://api.oauth2server.com/token
grant_type=client_credentials&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET
資源服務(wù)器返回形式和其他模式是相同的。
創(chuàng)建已經(jīng)授權(quán)的請求
最后就是使用AccessToken獲取資源,如何表示一個請求已經(jīng)被授權(quán)?就是在Http頭中加入Token:
curl -H "Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia" \
https://api.oauth2server.com/1/me
另外盡量確保使用Https通信,這樣才能保證信息安全。
與OAuth1.0版本差異
最后說明下兩個版本OAuth協(xié)議有什么不同點。
認(rèn)證和簽名
OAuth1.0流程中有大量密碼學(xué)上的簽名操作,以保證數(shù)據(jù)完整性;OAuth2 由Https來保護(hù)數(shù)據(jù)。
用戶體驗
和OAuth 1.0相比,OAuth 2在移動端的體驗更好。
性能
和OAuth 1.0相比,OAuth 2性能更好,減少了流程的步驟。
這里有一份很好理解的圖解:
【簡易圖解】『 OAuth2.0』 猴子都能懂的圖解
【簡易圖解】『 OAuth2.0』 『進(jìn)階』 授權(quán)模式總結(jié)
參考
http://www.itdecent.cn/p/6392420faf99
OpenID Connect協(xié)議
如果要談單點登錄和身份認(rèn)證,就不得不談OpenID Connect(OIDC).最典型的使用實例就是使用Google賬戶登陸其他應(yīng)用,這一經(jīng)典的協(xié)議模式,為其他廠商的第三方登陸起到了標(biāo)桿的作用。被廣泛參考和使用。
OpenID Connect簡介
OpenID Connect是基于OAuth2 規(guī)范族的客戶操作的身份驗證協(xié)議。他是用簡單的REST/JSON 消息流來實現(xiàn),和之前任何一種身份認(rèn)證協(xié)議相比,開發(fā)者可以輕松集成。
OpenID Connect允許開發(fā)者驗證跨網(wǎng)站和應(yīng)用的用戶,而無需擁有和管理密碼文件。
OpenID Connect允許索尼又類型的客戶,包括基于瀏覽器的JavaScript和本機(jī)移動應(yīng)用程序,啟動登錄流動和接收可驗證斷言對登錄用戶的身份。
OIDC基礎(chǔ)
簡要而言,OIDC是一種安全機(jī)制,用于應(yīng)用連接到身份認(rèn)證服務(wù)器(Identity Service)獲取用戶信息,并將這些信息以安全可靠的方法返回給應(yīng)用。
在最初因為OpenID經(jīng)常和OAuth協(xié)議一起提及,所以二者經(jīng)常被搞混。
- OpenID 是Authentication,即認(rèn)證,對用戶的身份進(jìn)行認(rèn)證,判斷其身份是否有效,也就是讓網(wǎng)站知道“你是你聲稱的那個用戶”
- OAuth是Authorization 即授權(quán),在已知用戶身份合法的情況下,經(jīng)用戶授權(quán)來允許某些操作,也就是讓網(wǎng)站知道“你能被允許做哪些事情”
由此可知,授權(quán)要在認(rèn)證之后進(jìn)行,只有確定用戶身份之后才能授權(quán)
(身份認(rèn)證)+OAuth2.0 = OpenID Connect
OpenID Connect是“認(rèn)證”和“授權(quán)”的結(jié)果,因為其基于OAuth協(xié)議,所以O(shè)penID Connect協(xié)議中包含了client_id、client_secret還有redirect_uri等字段標(biāo)識。這些信息被保存在“身份認(rèn)證服務(wù)器”,以確保特定的客戶端收到的信息只來自于合法的應(yīng)用平臺。這樣做的目的是為了防止client_id泄露而造成的惡意網(wǎng)站發(fā)起的OIDC流程。
舉個栗子,某個用戶使用FaceBook的子應(yīng)用(例如faceBook中的某一款游戲),該應(yīng)用可以通過FaceBook賬號登錄,則你可以在應(yīng)用找那個發(fā)起請求到“身份認(rèn)證服務(wù)器”(也就是FaceBook的服務(wù)器)請求登錄,這時你會看到如下界面,詢問是否授權(quán)。

在OAuth中,這些授權(quán)被稱為scope.OpenID Connect也有自己特殊的scope--openid,他必須在第一次請求“身份鑒別服務(wù)器(Identity Provider簡稱IDP)”時發(fā)送過去。
OIDC 流程
OAuth2提供了Access Token來解決授權(quán)單方客戶端訪問受保護(hù)資源的問題;相似的,OIDC在這個基礎(chǔ)上提供了ID Token來解決第三方客戶端表示用戶身份認(rèn)證的問題。
OIDC的核心在于OAUth2的授權(quán)流程中,一并提供用戶的身份認(rèn)證信息(ID-Token),給到第三方客戶端,ID-Token使用JWT(JSON Web Token - 在Web應(yīng)用間安全地傳遞信息
)格式來包裝,得益于JWT的自包含性,緊湊型以及防篡改機(jī)制,是的ID-Token可以安全的傳遞給第三方客戶端程序并且容易被驗證。應(yīng)用服務(wù)器,在驗證ID-Token正確性后,使用Access-Token向UserInfo接口換取用戶的更多信息。
有上述可知,OIDC是遵循了OAuth協(xié)議流程,在申請Access-Token的同時,也返回了ID-Token來驗證用戶身份。
相關(guān)定義
- EU:End User 用戶。
- RP:Relying Party 用來代指OAuth2中受信任的客戶端,身份認(rèn)證和授權(quán)信息的消費方。
- OP:OpenID Provider,有能力提供EU身份認(rèn)證的服務(wù)方(比如OAuth2中的授權(quán)服務(wù)),用來為RP提供EU的身份認(rèn)證信息。
- ID-Token:JWT格式的數(shù)據(jù),包含EU身份認(rèn)證的信息。
- UserInfo EndPoint:用戶信息接口(受IAuth2保護(hù)),當(dāng)RP使用ID-Token訪問時,返回授權(quán)用戶的信息,此接口必須使用HTTPS。
下面我們來俺看OIDC的具體協(xié)議流程。
根據(jù)應(yīng)用客戶端不同,OIDC的工作模式月應(yīng)該是不同的。和OAuth類似,主要看是否客戶端能否保證client_secret的安全性。
如果是JS應(yīng)用,其所有的代碼都會被加載到瀏覽器而暴露出來,沒有后端可以保證client_secret的安全性,則需要使用默認(rèn)模式流程(Implicit Flow)
如果是傳統(tǒng)的客戶端應(yīng)用,后端代碼和用戶是隔離的保證client_secret不被泄漏。就可以使用授權(quán)碼模式流程(Authentication Flow).
此外還有混合模式流程(Hybird Flow),簡而言之就是以上二者的融合。
OAuth2中還有口令模式和應(yīng)用訪問模式 這兩種方式來獲取access Token,為什么OIDC中沒有擴(kuò)展這些方式呢?
口令模式是需要用戶提供賬號和密碼給RP的,既然都已經(jīng)有用戶名和密碼了,就不需要再獲取什么用戶身份了。至于應(yīng)用訪問模式,這種方式不需要用戶參與,也就無需要認(rèn)證和獲取用戶身份了。這也能反映出授權(quán)和認(rèn)證的差異,以及只是用OAuth2來做身份認(rèn)證的事情是遠(yuǎn)遠(yuǎn)不夠的,也是不合適的。
授權(quán)碼模式流程

和OAuth認(rèn)證流程類似
1.RP發(fā)送一個認(rèn)證請求給OP,其中附帶client_id
2.OP對EU進(jìn)行身份認(rèn)證
3.OP返回響應(yīng),發(fā)送授權(quán)碼給RP
4.RP使用授權(quán)碼想OP索要ID-Token和Access-Token,OP驗證無誤后返回給RP;
5.RP使用Access-Token發(fā)送一個請求到UserInfo EndPoint;UserInfo EndPoint返回EU的Claims。
基于Authorization Code的認(rèn)證請求
RP使用OAth2的Authorization-code的方式來完成用戶身份認(rèn)證,所有TOken都是通過OP的Token EndPoint來發(fā)放的。構(gòu)建一個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
基于Authorization Code的認(rèn)證請求的響應(yīng)
在OP接收到認(rèn)證請求之后,需要對請求參數(shù)做嚴(yán)格的驗證,具體的規(guī)則參見http://openid.net/specs/openid-connect-core-1_0.html#AuthRequestValidation,驗證通過后引導(dǎo)EU進(jìn)行身份認(rèn)證并且同意授權(quán)。在這一切都完成后,會重定向到RP指定的回調(diào)地址(redirect_uri),并且把code和state參數(shù)傳遞過去。比如:
HTTP/1.1 302 Found
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
獲取ID Token
RP使用上一步獲得的code來請求TOken EndPoint,這一步同OAuth2,就不再展開細(xì)說了。然后Token EndPoint會返回響應(yīng)的Token,其中除了OAuth2規(guī)定的部分?jǐn)?shù)據(jù)外,還會附加一個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進(jìn)行驗證(具體規(guī)則參見http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation和http://openid.net/specs/openid-connect-core-1_0.html#ImplicitTokenValidation)。至此,可以說用戶身份認(rèn)證就可以完成了。后序可以根據(jù)UserInfo EndPoint獲取更完整的信息。
安全令牌 ID-Token
上面提到過OIDC對OAuth2最主要的擴(kuò)展就是提供了ID-Token,下面我們來看看ID-Token的主要構(gòu)成:
- iss = Issuer Identifier:必須。提供認(rèn)證信息者的唯一標(biāo)識。一般是Url的host+path部分
- sub = Subject Identifier:必須。iss提供EU的唯一標(biāo)識;最長為255個ASCII個字符;
- aud = Audience(s):必須。標(biāo)識ID-Token的受眾。必須包含OAuth2的client_id;
- exp =Expiration time:必須。ID-Token的過期時間。
- iat = Issued At Time。必須。JWT構(gòu)建的時間。
- auth_time = AuthenticationTime:EU完成認(rèn)證的時間。如果RP發(fā)送認(rèn)證請求的時候攜帶max_age的參數(shù),則此Claim是必須的。
- nonce:RP發(fā)送請求的時候提供的隨機(jī)字符串,用來減緩重放攻擊,也可以來關(guān)聯(lián)ID-Token和RP本身的Session信息。
- acr = Authentication Context Class Reference:可選。表示一個認(rèn)證上下文引用值,可以用來標(biāo)識認(rèn)證上下文類。
- amr = Authentication Methods References:可選。表示一組認(rèn)證方法。
- azp = Authorized party:可選。結(jié)合aud使用。只有在被認(rèn)證的一方和受眾(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進(jìn)行簽名和JWE(JSON Web Encryption)加密。從而提供認(rèn)證的完整性、不可否認(rèn)性以及可選的保密性。
USerInfo EndPoint
可能有的讀者發(fā)現(xiàn)了,ID-Token只有sub是EU相關(guān)的,這在一般情況下是不夠的,必須還需要EU的用戶名,頭像等其他的資料,OIDC提供了一組公共的cliams,來提供更多用戶的信息,這就是UserInfo EndPoint。
在RP得到Access Token后可以請求此資源,然后獲得一組EU相關(guān)的Claims,這些信息可以說是ID-Token的擴(kuò)展,ID-Token中只需包含EU的唯一標(biāo)識sub即可(避免ID-Token過于龐大和暴露用戶敏感信息),然后再通過此接口獲取完整的EU的信息。此資源必須部署在TLS之上(即必須使用HTTPS)例如:
GET /userinfo HTTP/1.1
Host: server.example.com
Authorization: Bearer SlAV32hkKG
成功之后響應(yīng)如下:
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的唯一標(biāo)識,這個claim是必須的,其他都是可選的。