"family_name": "Silverman",
"given_name": "Micah",
"locale": "en-US",
"name": "Micah Silverman",
"preferred_username": "micah.silverman@okta.com",
"sub": "00u9vme99nxudvxZA0h7",
"updated_at": 1490198843,
"zoneinfo": "America/Los_Angeles"
}

上面包含了一些聲明profile。這是因為對用戶信息的請求是使用通過范圍獲得的令牌進行的profile。換句話說,發出的請求會導致發出令牌。該令牌包含基于原始請求中指定的范圍的某些信息。

什么是響應類型?

使用 OIDC 時,您會聽到各種“流程”的討論。這些流程用于描述不同的常見身份驗證和授權場景。考慮因素包括應用程序的類型(如基于 Web 或原生移動應用程序)、您希望如何驗證令牌(在應用程序中還是在后端),以及您希望如何訪問其他身份信息(進行另一個 API 調用或將其直接編碼到令牌中)。

主要有三種流程:授權碼隱式混合response_type。這些流程由請求中的查詢參數控制/authorization。在考慮使用哪種流程時,請考慮前向通道與后向通道的要求。前向通道是指直接與 OpenID 提供商 (OP) 交互的用戶代理(例如 SPA 或移動應用程序)。當需要前向通道通信時,隱式流程是一個不錯的選擇。后向通道是指與 OP 交互的中間層客戶端(例如 Spring Boot 或 Express)。當需要后向通道通信時,授權碼流程是一個不錯的選擇。

授權碼流程使用response_type=code。身份驗證成功后,響應將包含一個code值。此代碼稍后可以交換為 和access_tokenid_token請稍等,稍后我們將更深入地討論令牌。)當架構中包含“中間件”時,此流程非常有用。中間件具有 和client idclient secret這是code通過點擊/token端點將 交換為令牌所必需的。然后可以將這些令牌返回給最終用戶應用程序(例如瀏覽器),而無需瀏覽器知道client secret。此流程允許通過使用 實現長壽命會話refresh tokens。 的唯一目的refresh tokens是獲取新的access tokens以延長用戶會話。

隱式流程使用response_type=id_token tokenresponse_type=id_token。身份驗證成功后,響應將在第一種情況下包含id_token和,在第二種情況下僅包含 。當您的應用程序直接與后端對話以獲取沒有中間件的令牌時,此流程很有用。它不支持長壽命會話。access_tokenid_token

混合流將上述兩種流以不同的組合方式組合在一起 – 以適合用例的方式。例如response_type=code id_token。此方法可實現一種場景,您可以在應用程序中擁有一個長壽命會話,并立即從/authorization端點獲取令牌。

關于Token

有了范圍、聲明和響應類型的基礎,我們現在可以討論令牌了!OIDC 中有三種類型的令牌:id_tokenaccess_tokenrefresh_token

ID Token

根據OIDC 規范, Anid_tokenJWT。這意味著:

規范中有一組規則id_token用于驗證。 在 中編碼的聲明中id_token有一個到期日期 ( exp),必須在驗證過程中遵守。 此外,JWT 的簽名部分與密鑰一起使用,以驗證整個 JWT 未以任何方式被篡改。

訪問Token

訪問令牌用作不記名令牌。不記名令牌意味著不記名令牌持有者無需進一步識別即可訪問授權資源。因此,保護不記名令牌非常重要。如果我能以某種方式獲得并“持有”您的訪問令牌,我就可以偽裝成您。

為了提高安全性,這些令牌通常具有較短的使用壽命(由其到期時間決定)。也就是說,當訪問令牌到期時,用戶必須再次進行身份驗證才能獲得新的訪問令牌,從而限制其為不記名令牌這一事實的暴露。

盡管 OIDC 規范沒有強制要求,Okta 使用 JWT 作為訪問令牌,因為(除其他外)到期時間內置于令牌中。

OIDC 指定/userinfo返回身份信息且必須受到保護的端點。出示訪問令牌即可使端點可訪問。

以下是使用HTTPie的示例:

http https://micah.oktapreview.com/oauth2/.../v1/userinfo

HTTP/1.1 400 Bad Request
...
WWW-Authenticate: Bearer error="invalid_request", error_description="The access token is missing."
...

讓我們使用過期的訪問令牌再試一次:

http https://micah.oktapreview.com/oauth2/.../v1/userinfo \
Authorization:"Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ik93bFNJS3p3Mmt1Wk8zSmpnMW5Dc2RNelJhOEV1elY5emgyREl6X3RVRUkifQ..."

HTTP/1.1 401 Unauthorized
...
WWW-Authenticate: Bearer error="invalid_token", error_description="The token has expired."
...

最后,讓我們嘗試使用有效的訪問令牌:

http https://micah.oktapreview.com/oauth2/.../v1/userinfo \
Authorization:"Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ik93bFNJS3p3Mmt1Wk8zSmpnMW5Dc2RNelJhOEV1elY5emgyREl6X3RVRUkifQ..."

HTTP/1.1 200 OK
...
{
"family_name": "Silverman",
"given_name": "Micah",
"groups": [
"ABC123",
"Everyone"
],
"locale": "en-US",
"name": "Micah Silverman",
"preferred_username": "micah+okta@afitnerd.com",
"sub": "...",
"updated_at": 1490198843,
"zoneinfo": "America/Los_Angeles"
}

刷新Token

刷新令牌用于獲取新的訪問令牌。通常,刷新令牌是長期有效的,而訪問令牌是短期有效的。這允許長期存在的會話在必要時可以被終止。以下是一個典型的場景:

  1. 用戶登錄并獲取訪問令牌和刷新令牌
  2. 應用程序檢測到訪問令牌已過期
  3. 應用程序使用刷新令牌獲取新的訪問令牌
  4. 重復 2 和 3,直到刷新令牌過期
  5. 刷新令牌過期后,用戶必須重新進行身份驗證

你可能會問:為什么要這樣做?這種方法在用戶體驗和安全性之間取得了平衡。想象一下,如果用戶以某種方式受到威脅。或者,他們的訂閱到期了。或者,他們被解雇了。在任何時候,管理員都可以撤銷刷新令牌。然后,上面的第三步將失敗,用戶將被迫(嘗試)通過身份驗證建立新會話。如果他們的帳戶已被暫停,他們將無法進行身份驗證。

識別類型

區分不同的 token 類型有時會令人困惑。以下是快速參考:

  1. ID 令牌攜帶在令牌本身中編碼的身份信息,該令牌必須是 JWT
  2. 訪問令牌用于通過將資源用作承載令牌來獲取對資源的訪問權限
  3. 刷新令牌僅用于獲取更多訪問令牌

OIDC 實際應用

您從 OIDC 流中返回的令牌和/userinfo端點的內容取決于請求的流類型和范圍。您可以在OIDC 流測試站點scope上實時查看。在這里,您可以為和設置不同的切換response_type,這決定了您的應用的流類型。

您的用例將決定使用哪種流程。您是否正在構建需要直接與 OpenID 提供程序 (OP) 交互的 SPA 或移動應用程序?您是否有可以與 OP 交互的中間件,例如 Spring Boot 或 Node.js Express?下面,我們將深入探討一些可用的流程以及何時適合使用它們。

授權碼流程

如果您有一個連接到 OIDC OP 的中間件客戶端,并且(不一定)希望令牌返回到最終用戶應用程序(例如瀏覽器),則這種方法很合適。這也意味著最終用戶應用程序永遠不需要知道密鑰。

以下是使用 Okta 開始此流程的示例:

https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/authorize?client_id=0oa2yrbf35Vcbom491t7&response_type=code&scope=openid&state=little-room-greasy-pie&nonce=b1e7b75d-6248-4fc7-bad0-ac5ae0f2e581&redirect_uri=https%3A%2F%2Fokta-oidc-fun.herokuapp.com%2Fflow_result

讓我們詳細分析一下:

鑰匙價值描述
組織 URLhttps://micah.okta.comOkta 租戶
授權網址/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/授權貴組織的默認授權端點
客戶端 ID0oa2yrbf35Vcbom491t7Okta 中定義的 OIDC 應用程序的客戶端 ID
響應類型代碼指示代碼流的響應類型
范圍開放標識openid 范圍是必需的
狀態小房間油膩餡餅流程結束時返回隨機值
隨機數b1e7b75d-6248-4fc7-bad0-ac5ae0f2e581編碼到 id_token 中的隨機值,用于稍后驗證
重定向 urihttps%3A%2F%2Fokta-oidc-fun.herokuapp.com%2Fflow_resultOP 重定向到的 URL 編碼 URL

瀏覽器中的情況如下:

請注意,在新屏幕上,您將被重定向回redirect_uri最初指定的頁面:

在后臺,會使用固定的用戶名和密碼建立會話。則當您單擊鏈接時,您將被重定向到登錄,然后重定向回同一頁面。

在上面的屏幕截圖中,您可以看到返回的代碼和原始的state

現在,中間層(在本例中為 Spring Boot 應用程序)可以將該代碼交換為id_token和。這個中間層將驗證我們之前在授權請求中發送的狀態,并使用客戶端密鑰發出請求,為用戶創建和。access_token/tokenaccess_tokenid_token

隱式流

當您想要直接與 OIDC OP 交互的客戶端(例如單頁應用程序或移動應用程序)工作時,這是一種合適的方法。

以下是使用 Okta 開始此流程的示例:

https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/authorize?client_id=0oa2yrbf35Vcbom491t7&response_type=id_token+token&scope=openid&state=shrill-word-accessible-iron&nonce=f8c658f0-1eb9-4f8d-8692-5da4e2f24cf0&redirect_uri=https%3A%2F%2Fokta-oidc-fun.herokuapp.com%2Fflow_result

它與授權碼流程幾乎相同,只是 是response_typeid_tokentoken下面id_token+token,我們將詳細介紹這些令牌中的內容及其驅動方式,但請記住:id_token編碼身份信息,access_token(如果token指定 則返回)是用于訪問資源的承載令牌。Okta 還使用 JWT 進行access_token,這樣可以將其他信息編碼到其中。

以下是瀏覽器中的流程:

您將被重定向回redirect_uri最初指定的位置(帶有返回的令牌和原始的state):

應用程序現在可以在id_token本地驗證。使用/introspect端點來驗證access_token。它還可以使用access_token作為承載令牌來訪問受保護的資源,例如/userinfo端點。

混合流

當您希望最終用戶應用程序能夠立即訪問短期令牌(例如id_token身份信息),并且還希望使用后端服務通過刷新令牌將授權碼交換為更長期令牌時,這是一種合適的方法。

它是授權代碼和隱式代碼流的組合。您可以通過查看它response_type必須包含code中的一個或兩個來發現它id_tokentoken

https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/authorize?client_id=0oa2yrbf35Vcbom491t7&response_type=code+id_token+token&scope=openid&state=shrill-word-accessible-iron&nonce=f8c658f0-1eb9-4f8d-8692-5da4e2f24cf0&redirect_uri=https%3A%2F%2Fokta-oidc-fun.herokuapp.com%2Fflow_result

瀏覽器中的情況如下:

您將被重定向回redirect_uri最初指定的頁面(包含返回的代碼、令牌和原始內容state):

在下一篇文章中,我們將深入研究如何控制這些令牌中的內容,但現在先來介紹一下:

這些令牌是在啟用所有默認范圍的混合流下產生的。

/userinfo以下是使用access_token作為承載令牌的端點的響應:

{
"sub": "00u2yulup4eWbOttd1t7",
"name": "Okta OIDC Fun",
"locale": "en-US",
"email": "okta_oidc_fun@okta.com",
"preferred_username": "okta_oidc_fun@okta.com",
"given_name": "Okta OIDC",
"family_name": "Fun",
"zoneinfo": "America/Los_Angeles",
"updated_at": 1499922371,
"email_verified": true
}

Token中有什么?

根據 OIDC 規范,與身份相關的信息有兩個主要來源。一個來源是編碼到id_token JWT中的信息。另一個來源是來自端點的響應/userinfo,可以使用access_token不記名令牌訪問。在 Okta,我們也選擇將訪問令牌設為 JWT,這提供了第三個信息來源。(您會在許多 OIDC 實現中看到這一點。)

請求中有很多查詢參數組合/authorization,它們決定了哪些信息將被編碼到 中。影響最終在返回的令牌和端點id_token中找到的內容的兩個查詢參數是和。/userinforesponse_typescope

OIDC 響應類型

目前,我們將把scope重點放在一邊response_type。在下面的例子中,我們只使用范圍openid(必需)和email。我們還將使用隱式流,因為它會立即返回令牌。

給出這個請求:

https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/authorize?client_id=0oa2yrbf35Vcbom491t7&response_type=token&scope=openid+email&state=aboard-insect-fresh-smile&nonce=c96fa468-ca1b-46f0-8974-546f23f9ee6f&redirect_uri=https%3A%2F%2Fokta-oidc-fun.herokuapp.com%2Fflow_result

請注意,這response_type=token將產生一個access_token。OIDC 規范中對訪問令牌沒有特定的格式要求,但在 Okta 中我們使用 JWT。查看返回的令牌,我們會看到:

{
"active": true,
"scope": "openid email",
"username": "okta_oidc_fun@okta.com",
"exp": 1501531801,
"iat": 1501528201,
"sub": "okta_oidc_fun@okta.com",
"aud": "test",
"iss": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7",
"jti": "AT.upPJqU-Ism6Fwt5Fpl8AhNAdoUeuMsEgJ_VxJ3WJ1hk",
"token_type": "Bearer",
"client_id": "0oa2yrbf35Vcbom491t7",
"uid": "00u2yulup4eWbOttd1t7"
}

這主要是資源信息,包括到期日期(exp)和用戶 ID(uid)。

如果我們想要獲取用戶的身份/userinfo信息,我們必須使用作為承載令牌的端點。使用HTTPieaccess_token的情況如下:

http https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/userinfo Authorization:"Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ik93bFNJS3p3Mmt1Wk8zSmpnMW5Dc2RNelJhOEV1elY5emgyREl6X3RVRUkifQ..."
HTTP/1.1 200 OK
...
{
"sub": "00u2yulup4eWbOttd1t7",
"email": "okta_oidc_fun@okta.com",
"email_verified": true
}

我們返回了subemailemail_verified聲明。這是因為scope=openid+email原始請求的默認值。我們將在范圍部分查看一些更詳細的響應。

我們來嘗試另一個請求:

https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/authorize?client_id=0oa2yrbf35Vcbom491t7&response_type=id_token&scope=openid+email&state=aboard-insect-fresh-smile&nonce=c96fa468-ca1b-46f0-8974-546f23f9ee6f&redirect_uri=https%3A%2F%2Fokta-oidc-fun.herokuapp.com%2Fflow_result

這次,我使用 請求 ID 令牌response_type=id_token。響應是 JWT(符合 OIDC 規范的要求),其中包含以下信息:

{
"sub": "00u2yulup4eWbOttd1t7",
"email": "okta_oidc_fun@okta.com",
"ver": 1,
"iss": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7",
"aud": "0oa2yrbf35Vcbom491t7",
"iat": 1501528456,
"exp": 1501532056,
"jti": "ID.4Mmzy2kj5_B8nGZ_PT4dt8-fzu1tA2W3C5dbEF-N6Us",
"amr": [
"pwd"
],
"idp": "00o1zyyqo9bpRehCw1t7",
"nonce": "c96fa468-ca1b-46f0-8974-546f23f9ee6f",
"email_verified": true,
"auth_time": 1501528157
}

請注意,我們將subemail聲明直接編碼在 JWT 中。在這種類型的隱式流程中,我們沒有針對/userinfo端點使用的承載令牌,因此身份信息直接嵌入到 JWT 中。

最后我們來看看最后一類隱式流:

https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/authorize?client_id=0oa2yrbf35Vcbom491t7&response_type=id_token+token&scope=openid+email&state=aboard-insect-fresh-smile&nonce=c96fa468-ca1b-46f0-8974-546f23f9ee6f&redirect_uri=https%3A%2F%2Fokta-oidc-fun.herokuapp.com%2Fflow_result

在這里,我們請求響應中的id_token和。access_token

我們的access_token主張與以前相同。的id_token主張如下:

{
"sub": "00u2yulup4eWbOttd1t7",
"email": "okta_oidc_fun@okta.com",
"ver": 1,
"iss": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7",
"aud": "0oa2yrbf35Vcbom491t7",
"iat": 1501528536,
"exp": 1501532136,
"jti": "ID.fyybPizTmYLoQR20vlR7mpo8WTxB7JwkxplMQom-Kf8",
"amr": [
"pwd"
],
"idp": "00o1zyyqo9bpRehCw1t7",
"nonce": "c96fa468-ca1b-46f0-8974-546f23f9ee6f",
"auth_time": 1501528157,
"at_hash": "T7ij7o69gBtjo6bAJvaVBQ"
}

請注意,這次的信息較少id_token(在本例中,沒有email_verified聲明)。因為我們還請求了access_token,所以我們預計會從端點獲取其余可用的身份信息(基于范圍)/userinfo。在這種情況下,它產生的信息與之前我們僅請求access_token

OIDC 范圍

將所有可用范圍與所有可能的響應類型相結合,可呈現大量信息:確切地說是 48 種組合。首先,我將列舉每個范圍產生的結果,然后我們將查看結合request_type和的幾個真實示例scope

首先要注意的是,不同的范圍會對端點中編碼id_token和返回的信息產生影響。以下是范圍和結果聲明的表格。

范圍由此產生的索賠
開放標識(所有 OIDC 流程都需要)
輪廓姓名、姓氏、名字、中間名、昵稱、首選用戶名
簡介(續)個人資料、圖片、網站、性別、出生日期、區域信息、語言環境、updated_at
電子郵件電子郵件,email_verified
地址地址
電話phone_number, phone_number_verified

讓我們使用所有可能的(默認)范圍類型嘗試每個隱式流。

https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/authorize?client_id=0oa2yrbf35Vcbom491t7&response_type=token&scope=openid+profile+email+address+phone&state=aboard-insect-fresh-smile&nonce=c96fa468-ca1b-46f0-8974-546f23f9ee6f&redirect_uri=https%3A%2F%2Fokta-oidc-fun.herokuapp.com%2Fflow_result

與之前相比,結果的唯一區別access_token是所有范圍都被編碼到scp數組聲明中。

這次,當我使用access_token來訪問/userinfo端點時,我得到了更多信息:

http https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/userinfo Authorization:"Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ik93bFNJS3p3Mmt1Wk8zSmpnMW5Dc2RNelJhOEV1elY5emgyREl6X3RVRUkifQ..."
HTTP/1.1 200 OK
...
{
"sub": "00u2yulup4eWbOttd1t7",
"name": "Okta OIDC Fun",
"locale": "en-US",
"email": "okta_oidc_fun@okta.com",
"preferred_username": "okta_oidc_fun@okta.com",
"given_name": "Okta OIDC",
"family_name": "Fun",
"zoneinfo": "America/Los_Angeles",
"updated_at": 1499922371,
"email_verified": true
}

注意:雖然這不是從profile范圍定義的聲明的完整列表,但它是我的 Okta 中的用戶具有價值的所有聲明。

讓我們嘗試id_token隱式流程(仍然具有所有默認范圍):

https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/authorize?client_id=0oa2yrbf35Vcbom491t7&response_type=id_token&scope=openid+profile+email+address+phone&state=aboard-insect-fresh-smile&nonce=c96fa468-ca1b-46f0-8974-546f23f9ee6f&redirect_uri=https%3A%2F%2Fokta-oidc-fun.herokuapp.com%2Fflow_result

id_token以下是我收到的編碼內容:

{
"sub": "00u2yulup4eWbOttd1t7",
"name": "Okta OIDC Fun",
"locale": "en-US",
"email": "okta_oidc_fun@okta.com",
"ver": 1,
"iss": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7",
"aud": "0oa2yrbf35Vcbom491t7",
"iat": 1501532222,
"exp": 1501535822,
"jti": "ID.Zx8EclaZmhSckGHOCRzOci2OaduksmERymi9-ad7ML4",
"amr": [
"pwd"
],
"idp": "00o1zyyqo9bpRehCw1t7",
"nonce": "c96fa468-ca1b-46f0-8974-546f23f9ee6f",
"preferred_username": "okta_oidc_fun@okta.com",
"given_name": "Okta OIDC",
"family_name": "Fun",
"zoneinfo": "America/Los_Angeles",
"updated_at": 1499922371,
"email_verified": true,
"auth_time": 1501528157
}

所有(可用的)身份信息都被直接編碼到令牌中,因為我沒有承載令牌來訪問端點/userinfo

最后,讓我們嘗試隱式流程的最后一種變體response_type=id_token+token

https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/authorize?client_id=0oa2yrbf35Vcbom491t7&response_type=code+id_token+token&scope=openid+profile+email+address+phone&state=aboard-insect-fresh-smile&nonce=c96fa468-ca1b-46f0-8974-546f23f9ee6f&redirect_uri=https%3A%2F%2Fokta-oidc-fun.herokuapp.com%2Fflow_result

在這種情況下,我們將一些聲明編碼為id_token

{
"sub": "00u2yulup4eWbOttd1t7",
"name": "Okta OIDC Fun",
"email": "okta_oidc_fun@okta.com",
"ver": 1,
"iss": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7",
"aud": "0oa2yrbf35Vcbom491t7",
"iat": 1501532304,
"exp": 1501535904,
"jti": "ID.1C2NQext2hM0iJy55cLc_Ryc45urVYC1wJ0S-KebkpI",
"amr": [
"pwd"
],
"idp": "00o1zyyqo9bpRehCw1t7",
"nonce": "c96fa468-ca1b-46f0-8974-546f23f9ee6f",
"preferred_username": "okta_oidc_fun@okta.com",
"auth_time": 1501528157,
"at_hash": "GB5O9CpSSOUSfVZ9CRekRg",
"c_hash": "mRNStYQm-QU4rwcfv88VKA"
}

如果我們使用結果access_token來到達/userinfo端點,在這種情況下,我們會得到:

http https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/userinfo Authorization:"Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ik93bFNJS3p3Mmt1Wk8zSmpnMW5Dc2RNelJhOEV1elY5emgyREl6X3RVRUkifQ..."
HTTP/1.1 200 OK
...
{
"sub": "00u2yulup4eWbOttd1t7",
"name": "Okta OIDC Fun",
"locale": "en-US",
"email": "okta_oidc_fun@okta.com",
"preferred_username": "okta_oidc_fun@okta.com",
"given_name": "Okta OIDC",
"family_name": "Fun",
"zoneinfo": "America/Los_Angeles",
"updated_at": 1499922371,
"email_verified": true
}

這將完善范圍內所請求的所有身份信息。

自定義范圍和聲明

OIDC 規范可容納自定義范圍和聲明。在令牌(可通過加密驗證)中包含自定義聲明的能力是身份提供者的一項重要功能。Okta 的實現為此提供了支持。

下面的屏幕截圖顯示了我的授權服務器的聲明選項卡:

點擊“添加聲明”按鈕將彈出一個對話框:

在上面的屏幕截圖中,自定義聲明是使用 Okta 的表達式語言定義的。表達式語言是 Okta 獨有的,它是一種靈活的方式來描述構建屬性以包含(或不包含)在自定義聲明中的規則。

response_type=id_token使用帶有和的隱式流scope=openid+profile,我們現在返回一個id_token包含以下編碼聲明的:

{
"sub": "00u2yulup4eWbOttd1t7",
"ver": 1,
"iss": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7",
"aud": "0oa2yrbf35Vcbom491t7",
"iat": 1501533536,
"exp": 1501537136,
"jti": "ID.TsKlBQfGmiJcl2X3EuhzyyLfmzqi0OCd66rJ3Onk7FI",
"amr": [
"pwd"
],
"idp": "00o1zyyqo9bpRehCw1t7",
"nonce": "c96fa468-ca1b-46f0-8974-546f23f9ee6f",
"auth_time": 1501528157,
"at_hash": "hEjyn3mbKjuWanuSAF-z4Q",
"full_name": "Okta OIDC Fun"
}

請注意full_name中的聲明id_token

驗證令牌

可以通過訪問端點來驗證訪問令牌/introspect。對于active令牌,您將獲得如下響應:

http --auth <OIDC Client ID>:<OIDC Client Secret> -f POST \
https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/introspect \
token=eyJhbGciOiJSUzI1NiIsImtpZCI6Ik93bFNJS3p3Mmt1Wk8zSmpnMW5Dc2RNelJhOEV1elY5emgyREl6X3RVRUkifQ...
HTTP/1.1 200 OK
...

{
"active": true,
"aud": "https://afitnerd.com/test",
"client_id": "xdgqP32nYN148gn3gJsW",
"exp": 1498517509,
"fullName": "Micah Silverman",
"iat": 1498513909,
"iss": "https://micah.oktapreview.com/oauth2/aus9vmork8ww5twZg0h7",
"jti": "AT.JdXQPAuh-JTqhspCL8nLe2WgbfjcK_-jmlp7zwaYttE",
"scope": "openid profile",
"sub": "micah+okta@afitnerd.com",
"token_type": "Bearer",
"uid": "00u9vme99nxudvxZA0h7",
"username": "micah+okta@afitnerd.com"
}

由于它需要 OIDC 客戶端 ID 和密鑰,因此此操作通常在可以安全獲取這些憑據的應用服務器中完成。您不會希望最終用戶 Web 或移動應用等能夠訪問 OIDC 客戶端密鑰。

如果token參數無效或者已過期,/introspect端點將返回以下內容:

http --auth <OIDC Client ID>:<OIDC Client Secret> -f POST \
https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/introspect \
token=bogus
HTTP/1.1 200 OK
...
{
"active": false
}

可以使用JWK端點驗證 ID 令牌。JWK 是一種表示加密密鑰的 JSON 數據結構。JWK 端點從用于 API 發現的 OIDC“眾所周知”端點公開。這會返回大量信息。以下是摘錄:

http https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/.well-known/openid-configuration
HTTP/1.1 200 OK
...
{
"authorization_endpoint": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/authorize",
...
"introspection_endpoint": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/introspect",
...
"issuer": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7",
"jwks_uri": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/keys",
...
"userinfo_endpoint": "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/userinfo"
}

其中一些端點(例如/userinfo/authorize)現在看起來應該很熟悉。我們感興趣的是/keys中顯示的端點jwks_uri

http https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7/v1/keys
HTTP/1.1 200 OK
...
{
"keys": [
{
"alg": "RS256",
"e": "AQAB",
"kid": "cbkhWG0YmFsGiNO1LEkWSEszDCTNfwvJPpXxuVf_kX0",
"kty": "RSA",
"n": "g2XQgdyc5P6F4K26ioKiUzrdgfy90eBgIbcrKkspKZmzRJ3CIssv69f1ClJvT784J-...",
"use": "sig"
}
]
}

注意kid聲明。它kid與我們標題中的聲明相匹配id_token

{
"typ": "JWT",
"alg": "RS256",
"kid": "cbkhWG0YmFsGiNO1LEkWSEszDCTNfwvJPpXxuVf_kX0"
}

我們還可以看到使用的算法是RS256。使用聲明中找到的公鑰n以及安全庫,我們可以確認 ID 令牌未被篡改。所有這些都可以在最終用戶 SPA、移動應用程序等上安全地完成。

下面是一個 Java 示例,它使用上述聲明jwks_uri來驗證id_token: https: //github.com/dogeared/JWKTokenVerifier

java -jar target/jwk-token-verifier-0.0.1-SNAPSHOT-spring-boot.jar \
eyJhbGciOiJSUzI1NiIsImtpZCI6Ik93bFNJS3p3Mmt1Wk8zSmpnMW5Dc2RNel... \
g2XQgdyc5P6F4K26ioKiUzrdgfy90eBgIbcrKkspKZmzRJ3CIssv69f1ClJvT784J-... \
AQAB

Verified Access Token
{
"header" : {
"alg" : "RS256",
"kid" : "cbkhWG0YmFsGiNO1LEkWSEszDCTNfwvJPpXxuVf_kX0"
},
"body" : {
"ver" : 1,
"jti" : "AT.LT9cRL_Kzd3T8Izw_ONZxHJ5xGBPD0m13iiEIDK_Nbw",
"iss" : "https://micah.okta.com/oauth2/aus2yrcz7aMrmDAKZ1t7",
"aud" : "test",
"iat" : 1501533536,
"exp" : 1501537136,
"cid" : "0oa2yrbf35Vcbom491t7",
"uid" : "00u2yulup4eWbOttd1t7",
"scp" : [ "openid" ],
"sub" : "okta_oidc_fun@okta.com"
},
"signature" : "ZV_9tYxt4v4bp9WEEDu038b7v_OHsbMZw13daR1s5_tI56oayBgJlnqf-..."
}

如果 JWT 的任何部分id_token被篡改,你會看到以下信息:

io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.

使用終端和 JWK 驗證 JWT/introspect是 OIDC 的一個強大組件。它能夠高度確保令牌未以任何方式被篡改。因此,令牌中包含的信息(例如有效期)可以安全地執行。

熱門推薦
一個賬號試用1000+ API
助力AI無縫鏈接物理世界 · 無需多次注冊
3000+提示詞助力AI大模型
和專業工程師共享工作效率翻倍的秘密
返回頂部
上一篇
API安全風險:需要注意和如何預防
下一篇
不安全的API和爬蟲攻擊導致企業每年損失高達1860億美元
国内精品久久久久影院日本,日本中文字幕视频,99久久精品99999久久,又粗又大又黄又硬又爽毛片
欧美日本一区二区三区| 日韩免费电影网站| 欧日韩精品视频| 中文字幕五月欧美| 不卡一二三区首页| 亚洲蜜臀av乱码久久精品| 91免费看片在线观看| 亚洲人一二三区| 欧美性大战久久久| 日本不卡一区二区三区高清视频| 欧美精品色一区二区三区| 亚洲一二三区视频在线观看| 色婷婷综合久久久久中文 | 久久www免费人成看片高清| 精品蜜桃在线看| 久久众筹精品私拍模特| 亚洲夂夂婷婷色拍ww47| 亚洲高清免费观看| 日本一区中文字幕| 99久久婷婷国产综合精品电影 | 欧美二区乱c少妇| 日韩激情在线观看| 26uuu精品一区二区在线观看| 岛国一区二区在线观看| 天天影视涩香欲综合网| 国产精品传媒在线| 91精品久久久久久久久99蜜臂| 国产精品羞羞答答xxdd| 香蕉成人啪国产精品视频综合网 | 91精品国产综合久久精品麻豆| 国产在线视频一区二区三区| 亚洲综合一区在线| 国产免费观看久久| 日韩亚洲国产中文字幕欧美| 99免费精品视频| 国产高清亚洲一区| 日本大胆欧美人术艺术动态| 亚洲精品日日夜夜| 亚洲欧洲日韩一区二区三区| 精品国产乱码久久久久久1区2区| 欧美在线观看一二区| 成人免费av在线| 国产精品资源在线观看| 久久97超碰色| 蜜臀av在线播放一区二区三区| 亚洲五码中文字幕| 一区二区三区在线看| 日本一区二区免费在线| 久久嫩草精品久久久精品| 精品国产一区二区三区忘忧草| 欧美精品三级日韩久久| 欧美伦理影视网| 8x8x8国产精品| 日韩午夜av一区| 欧美xxxxx牲另类人与| 日韩欧美国产高清| 精品国产一区二区精华| 久久精品在线免费观看| 亚洲国产精品国自产拍av| 国产精品私人影院| 日韩一区有码在线| 亚洲精品国产精品乱码不99| 亚洲综合色噜噜狠狠| 日韩国产精品久久久| 国产一区二区精品在线观看| 国产99久久久久| 色一区在线观看| 欧美日韩国产成人在线免费| 日韩精品一区二区三区三区免费 | 懂色av噜噜一区二区三区av| 在线视频你懂得一区| 3atv在线一区二区三区| 精品91自产拍在线观看一区| 中文字幕一区二区三区不卡| 婷婷综合五月天| 国产99久久久国产精品潘金| 欧美午夜一区二区三区免费大片| 欧美一级生活片| 亚洲欧洲精品天堂一级 | 日韩欧美国产成人一区二区| 久久久久久97三级| 亚洲免费观看在线观看| 视频一区二区不卡| 高清beeg欧美| 欧美一级二级在线观看| 国产精品视频一二三区| 免费的成人av| 欧美在线视频日韩| 日本一区二区三级电影在线观看| 日本欧美加勒比视频| 一本大道久久a久久精二百| 久久蜜桃香蕉精品一区二区三区| 亚洲va韩国va欧美va| jvid福利写真一区二区三区| 久久久美女毛片| 麻豆国产精品一区二区三区 | 成人app网站| 欧美成人在线直播| 亚洲精品亚洲人成人网在线播放| 国产综合成人久久大片91| 91精品国产综合久久香蕉麻豆| 亚洲欧美综合在线精品| 国产精品中文字幕日韩精品| 91精品国产综合久久久蜜臀粉嫩 | 日韩视频永久免费| 亚洲h动漫在线| 欧美亚洲动漫精品| 一区二区三区精品| 91丝袜国产在线播放| 中文字幕一区二区三中文字幕| 国产成人综合自拍| 日本一区二区视频在线观看| 国产91在线看| 国产精品福利av| 91香蕉视频在线| 亚洲国产一区在线观看| 欧美精品日韩综合在线| 日韩国产欧美在线观看| 精品国产一区二区三区忘忧草| 国产一区二区精品久久| 亚洲欧洲av色图| 欧美日韩www| 激情小说亚洲一区| 国产精品网站一区| 在线影视一区二区三区| 日韩综合在线视频| 精品欧美久久久| 不卡的av中国片| 五月激情六月综合| 欧美精品一区男女天堂| 91丨九色丨尤物| 日韩国产精品久久久| 国产欧美日韩另类视频免费观看| 91在线观看一区二区| 亚洲国产精品久久不卡毛片| 欧美一区国产二区| 成人精品在线视频观看| 亚洲高清免费在线| 精品久久人人做人人爰| 91视频国产资源| 欧美96一区二区免费视频| 中文欧美字幕免费| 欧美裸体bbwbbwbbw| 国产精品一区免费视频| 亚洲超碰精品一区二区| 国产精品伦理在线| 欧美三级电影在线观看| 国产乱子伦一区二区三区国色天香 | 亚洲第一福利视频在线| 国产婷婷色一区二区三区 | 美脚の诱脚舐め脚责91 | 久久美女高清视频| 欧美色爱综合网| 99久久99久久精品免费观看| 美女久久久精品| 午夜久久久久久久久久一区二区| 国产精品久久久久久久第一福利 | 91精品国产91久久综合桃花| 91浏览器入口在线观看| 国产成人日日夜夜| 久久精品999| 六月丁香综合在线视频| 日韩电影在线一区| 亚洲18影院在线观看| 亚洲成人激情av| 亚洲最新在线观看| 亚洲欧美激情一区二区| 国产精品久久久久久久久动漫 | 综合中文字幕亚洲| 中文字幕乱码日本亚洲一区二区| 久久午夜免费电影| 精品国产一区二区三区久久影院| 欧美不卡一区二区| 国产日韩欧美一区二区三区乱码| 国产亚洲人成网站| 中文字幕亚洲一区二区va在线| 亚洲国产高清aⅴ视频| 中文字幕一区二区三区在线不卡| 亚洲欧美一区二区视频| 一区二区在线看| 日韩精品色哟哟| 久久精品72免费观看| 国产一区二区三区四区五区美女| 国产一区在线观看麻豆| 国产一区二区91| 国产福利一区在线| 国产福利精品导航| 91免费观看视频| 欧美三级电影在线看| 精品理论电影在线| 亚洲欧洲无码一区二区三区| 一区二区欧美精品| 麻豆精品视频在线观看免费 | 粉嫩嫩av羞羞动漫久久久| 色婷婷av一区| 精品国产三级a在线观看| 亚洲丝袜美腿综合| 免费成人你懂的| 91色在线porny| 久久综合九色综合欧美就去吻|