1 什麼是IdentityServer4?
IdentityServer4是用於ASP.NET Core的OpenID Connect和OAuth 2.0框架。
2 什麼是OAuth 2.0?
OAuth不是一個API或者服務,而是一個授權(Authorization)的開放標準,OAuth2.0是目前廣泛使用的版本。
2.1 4種角色
- 資源所有者(Resource Owner),又稱"使用者"。
- 資源伺服器(Resource Server),即處理各種業務服務的伺服器。
- 客戶端(Client)。
- 授權伺服器(Authorization Server),即處理授權服務的伺服器。
2.2 4種授權方式
- 授權碼(authorization code)
- 隱式授權(implicit)
- 資源所有者密碼憑據(resource owner password credentials)
- 客戶端憑據(client credentials)
2.2.1 授權碼(authorization code)
下圖說明了授權碼的工作流程。
(A)客戶端通過向授權端點引導資源所有者的使用者代理開始流程。客戶端包括它的客戶端標識、請求範圍、本地狀態和重定向URI,一旦訪問被許可(或拒絕)授權伺服器將傳送使用者代理回到該URI。
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
引數說明:
- response_type,表示授權型別,必選項,值必須被設定為“code”。
- client_id,表示客戶端標識,必選項
- redirect_uri,表示重定向URL,可選項
- scope,可選的,訪問請求的範圍,可選項
- state,客戶端用於維護請求和回撥之間的狀態的不透明的值,用於防止跨站點請求偽造,可選項
(B)授權伺服器驗證資源擁有者的身份(通過使用者代理),並確定資源所有者是否授予或拒絕客戶端的訪問請求。
(C)假設資源所有者許可訪問,授權伺服器使用之前(在請求時或客戶端註冊時)提供的重定向URI重定向使用者代理回到客戶端。重定向URI包括授權碼和之前客戶端提供的任何本地狀態。
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
引數說明:
- code,表示授權伺服器生成的授權碼,必選項。推薦的最長的授權碼生命週期是10分鐘。客戶端不能使用授權碼超過一次。如果一個授權碼被使用一次以上,授權伺服器必須拒絕該請求並應該撤銷(如可能)先前發出的基於該授權碼的所有令牌。
- state,若客戶端的請求中包含這個引數,伺服器的返回也必須一樣包含這個引數。
(D)客戶端通過包含上一步中收到的授權碼從授權伺服器的令牌端點請求訪問令牌。當發起請求時,客戶端與授權伺服器進行身份驗證。客戶端包含用於獲得授權碼的重定向URI來用於驗證。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
引數說明:
- grant_type,表示使用的授權模式,必選項。值必須被設定為“authorization_code”,必選項。
- code,表示從授權伺服器收到的授權碼,必選項。
- redirect_uri,表示重定向URI,必選項。若“redirect_uri”引數包含在授權請求中,且他們的值必須相同。
- client_id,表示客戶端標識,必選項。
(E)授權伺服器對客戶端進行身份驗證,驗證授權程式碼,並確保接收的重定向URI與在步驟(C)中用於重定向(資源所有者的使用者代理)到客戶端的URI相匹配。如果通過,授權伺服器響應返回訪問令牌與可選的重新整理令牌。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
引數說明:
- access_token:表示訪問令牌,必選項。
- token_type:表示令牌型別,該值大小寫不敏感,必選項,可以是bearer型別或mac型別。
- expires_in:表示過期時間,單位為秒。如果省略該引數,必須其他方式設定過期時間。
- refresh_token:表示更新令牌,用來獲取下一次的訪問令牌,可選項。
- scope:表示許可權範圍,如果與客戶端申請的範圍一致,此項可省略。
2.2.2 隱式授權(implicit)
下圖說明了隱式授權的工作流程。
(A)客戶端通過向授權端點引導資源所有者的使用者代理開始流程。客戶端包括它的客戶端標識、請求範圍、本地狀態和重定向URI,一旦訪問被許可(或拒絕)授權伺服器將傳送使用者代理回到該URI。
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
引數說明:
- response_type,表示授權型別,必選項,值必須被設定為“token”。
- client_id,表示客戶端標識,必選項
- redirect_uri,表示重定向URL,可選項
- scope,訪問請求的範圍,可選項
- state,客戶端用於維護請求和回撥之間的狀態的不透明的值,用於防止跨站點請求偽造,可選項
(B)授權伺服器驗證資源擁有者的身份(通過使用者代理),並確定資源所有者是否授予或拒絕客戶端的訪問請求。
(C)假設資源所有者許可訪問,授權伺服器使用之前(在請求時或客戶端註冊時)提供的重定向URI重定向使用者代理回到客戶端。重定向URI在URI片段中包含訪問令牌。
HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600
引數說明:
- access_token:表示訪問令牌,必選項。
- token_type:表示令牌型別,該值大小寫不敏感,必選項。
- expires_in:表示過期時間,以秒為單位的訪問令牌生命週期。例如,值“3600”表示訪問令牌將在從生成響應時的1小時後到期。如果省略,則授權伺服器應該通過其他方式提供過期時間,或者記錄預設值。
- scope:表示許可權範圍,如果與客戶端申請的範圍一致,此項可省略。
- state:若客戶端的請求中包含這個引數,伺服器的返回也必須一樣包含這個引數。
(D)使用者代理順著重定向指示向Web託管的客戶端資源發起請求(按RFC2616該請求不包含片段)。使用者代理在本地保留片段資訊。
(E)Web託管的客戶端資源返回一個網頁(通常是帶有嵌入式指令碼的HTML文件),該網頁能夠訪問包含使用者代理保留的片段的完整重定向URI並提取包含在片段中的訪問令牌(和其他引數)。
(F)使用者代理在本地執行Web託管的客戶端資源提供的提取訪問令牌的指令碼。
(G)使用者代理傳送訪問令牌給客戶端。
2.2.3 資源所有者密碼憑據(resource owner password credentials)
下圖說明了資源所有者密碼憑據的工作流程。
(A)資源所有者提供給客戶端它的使用者名稱和密碼。
(B)通過包含從資源所有者處接收到的憑據,客戶端從授權伺服器的令牌端點請求訪問令牌。當發起請求時,客戶端與授權伺服器進行身份驗證。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
引數說明:
- grant_type,表示授權型別,必選項,值必須設定為“password”。
- username,表示資源所有者的使用者名稱,必選項。
- password,表示資源所有者的密碼,必選項。
- scope,表示許可權範圍,可選項
(C)授權伺服器對客戶端進行身份驗證,驗證資源所有者的憑證,如果有效,頒發訪問令牌。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
引數說明:
- access_token:表示訪問令牌,必選項。
- token_type:表示令牌型別,該值大小寫不敏感,必選項,可以是bearer型別或mac型別。
- expires_in:表示過期時間,單位為秒。如果省略該引數,必須其他方式設定過期時間。
- refresh_token:表示更新令牌,用來獲取下一次的訪問令牌,可選項。
- scope:表示許可權範圍,如果與客戶端申請的範圍一致,此項可省略。
2.2.4 客戶端憑據(client credentials)
下圖說明了客戶端憑據的工作流程。
(A)客戶端與授權伺服器進行身份驗證並向令牌端點請求訪問令牌。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
引數說明:
- grant_type,表示授權型別,必選項,值必須設定為“client_credentials”。
- scope,表示許可權範圍,可選項
(B)授權伺服器對客戶端進行身份驗證,如果有效,頒發訪問令牌。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600, "example_parameter":"example_value"
}
引數說明:
- access_token:表示訪問令牌,必選項。
- token_type:表示令牌型別,該值大小寫不敏感,必選項,可以是bearer型別或mac型別。
- expires_in:表示過期時間,單位為秒。如果省略該引數,必須其他方式設定過期時間。
3 什麼是OpenID Connect?
OpenID Connect是由OpenID基金會於2014年釋出的一個開放標準,簡稱OIDC, 它是基於OAuth 2.0協議的簡單身份層。它允許客戶端根據授權伺服器執行的身份驗證來驗證終端使用者的身份,並以可互操作且類似於REST的方式獲取有關最終使用者的基本配置檔案資訊。
OpenID Connect允許所有型別的客戶端(包括基於Web的客戶端,移動客戶端和JavaScript客戶端)請求並接收有關經過身份驗證的會話和終端使用者的資訊。該規範套件是可擴充套件的,允許參與者在對他們有意義的時候使用可選功能,例如身份資料加密,OpenID提供程式的發現以及會話管理。
OpenID是Authentication,即認證,對使用者的身份進行認證,判斷其身份是否有效,也就是讓網站知道“你是你所聲稱的那個使用者”;
OAuth是Authorization,即授權,在已知使用者身份合法的情況下,經使用者授權來允許某些操作,也就是讓網站知道“你能被允許做那些事情”。
(身份驗證)+ OAuth 2.0 = OpenID Connect
OpenID Connect是“認證”和“授權”的結合,因為其基於OAuth協議,所以OpenID-Connect協議中也包含了client_id、client_secret還有redirect_uri等欄位標識。這些資訊被儲存在“身份認證伺服器”,以確保特定的客戶端收到的資訊只來自於合法的應用平臺。
3.1 相關定義
- EU:End User,使用者。
- RP:Relying Party ,用來代指OAuth2中的受信任的客戶端,身份認證和授權資訊的消費方;
- OP:OpenID Provider,有能力提供EU身份認證的服務方(比如OAuth2中的授權服務),用來為RP提供EU的身份認證資訊;
- ID-Token:JWT格式的資料,包含EU身份認證的資訊。
- UserInfo Endpoint:使用者資訊介面(受OAuth2保護),當RP使用ID-Token訪問時,返回授權使用者的資訊,此介面必須使用HTTPS。
3.2 OIDC流程
OIDC是遵循OAuth協議流程,在申請Access-Token的同時,也返回了ID-Token來驗證使用者身份。
如果是JS應用,其所有的程式碼都會被載入到瀏覽器而暴露出來,沒有後端可以保證client_secret的安全性,則需要是使用預設模式流程(Implicit Flow)。
如果是傳統的客戶端應用,後端程式碼和使用者是隔離的,能保證client_secret的不被洩露,就可以使用授權碼模式流程(Authentication Flow)。
此外還有混合模式流程(Hybrid Flow),簡而言之就是以上二者的融合。
3.2.1 授權碼模式流程(Authentication Flow)
和OAuth認證流程類似
RP傳送一個認證請求給OP,其中附帶client_id;
OP對EU進行身份認證;
OP返回響應,傳送授權碼給RP;
RP使用授權碼向OP索要ID-Token和Access-Token,RP驗證無誤後返回給RP;
RP使用Access-Token傳送一個請求到UserInfo EndPoint;UserInfo EndPoint返回EU的Claims。
3.3 安全令牌 ID-Token
OIDC對OAuth2最主要的擴充套件就是提供了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傳送認證請求的時候攜帶max_age的引數,則此Claim是必須的。
- nonce:RP傳送請求的時候提供的隨機字串,用來減緩重放攻擊,也可以來關聯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"
}