keycloak~賬號密碼認證和授權碼認證
重要的事說在前頭
- 在
/protocol/openid-connect/token請求過程中(認證,獲取code,刷新token等),client_id要保持一致,不能混用 - 使用哪個
client_id進行的表單登錄,生成的code碼,就用哪個client_id來獲取token - token中是哪個
client_id,就用哪個client_id來刷新token - scope授權范圍是在
授權碼認證中使用的,在keycloak中可以為客戶端添加默認的scope和可選的scope- 在獲取code環(huán)節(jié)
protocol/openid-connect/auth使用scope參數,而不是通過code獲取token環(huán)節(jié)/protocol/openid-connect/token - keycloak中,默認的scope(
Default Client Scopes)可以通過scope=openid獲取,而可選的scope(Optional Client Scopes),必須在獲取code時手動指定,多個scope值之間使用空格連接
- 在獲取code環(huán)節(jié)
概念
OAuth 2.0 中的授權碼認證(Authorization Code Grant)是一種常用的身份驗證和授權方式,主要用于用戶通過第三方應用訪問受保護的資源。以下是關于授權碼認證的詳細介紹:
授權碼認證流程
-
用戶請求授權:
- 用戶在客戶端應用(如移動應用或網頁)上點擊“登錄”或“授權”按鈕。
- 客戶端將用戶重定向到授權服務器的授權端點,并附帶一些參數,包括:
response_type=code:表示請求授權碼。client_id:客戶端的唯一標識符。redirect_uri:用戶授權后重定向的地址。scope:客戶端請求的權限范圍。state:防止CSRF攻擊的隨機字符串。
-
用戶登錄并授予權限:
- 用戶在授權服務器上登錄(如果尚未登錄),并查看客戶端請求的權限范圍。
- 用戶同意授權后,授權服務器會生成一個授權碼,并將其附加到重定向URI中返回給客戶端。
-
客戶端使用授權碼獲取訪問令牌:
- 客戶端接收到授權碼后,會向授權服務器的令牌端點發(fā)送請求,包含以下信息:
grant_type=authorization_code:表示使用授權碼模式。code:剛才獲得的授權碼。redirect_uri:與初始請求中的重定向URI相同。client_id和client_secret:用于驗證客戶端身份。
- 客戶端接收到授權碼后,會向授權服務器的令牌端點發(fā)送請求,包含以下信息:
-
授權服務器返回訪問令牌:
- 授權服務器驗證授權碼和其他信息是否有效。如果有效,將生成并返回訪問令牌(Access Token)和可選的刷新令牌(Refresh Token)。
-
客戶端使用訪問令牌訪問資源:
- 客戶端可以使用獲取到的訪問令牌來訪問受保護的資源,通常是在請求頭中添加
Authorization: Bearer {access_token}。
- 客戶端可以使用獲取到的訪問令牌來訪問受保護的資源,通常是在請求頭中添加
優(yōu)勢
- 安全性高:由于訪問令牌是通過授權碼交換得到的,避免了在用戶的瀏覽器中直接暴露訪問令牌。
- 適用于用戶代理:特別適合需要用戶交互的場景,如Web應用和移動應用。
- 支持單點登錄:用戶只需登錄一次,即可在多個客戶端之間共享訪問令牌。
注意事項
- 使用 HTTPS 來保護通信,防止中間人攻擊。
state參數用于防止 CSRF 攻擊,確保請求的完整性。- 授權碼通常是短期有效的,訪問令牌也可能有過期時間,需合理管理。
示例圖解
用戶 --> 客戶端 --> 授權服務器
| |
|-- 登錄 ---->|
|<--- 授權碼-|
| |
|-- 訪問令牌->|
|<--- 資源 ---|
keycloak中授權碼認證的過程
一 密碼認證[direct grant]
- POST /auth/realms/demo/protocol/openid-connect/token
- 請求體 x-www-form-urlencoded
- 不支持scope參數,密碼認證的scope就是client_id配置的scope
grant_type:password
username:test
password:123456
client_secret:ec0fd1c6-68b0-4c39-a9fa-c3be25c8ef01
client_id:democlient
- 響應
{
"access_token": "xxx",
"expires_in": 3000,
"refresh_expires_in": 1800,
"refresh_token": "xxx",
"token_type": "bearer",
"not-before-policy": 1619512543,
"session_state": "765969ec-94da-4edb-9dcb-e15ea3e0ad3b",
"scope": "roles email profile" // 當前democlient這個客戶端的默認權限范圍
}
二 授權碼登錄
請求code
對于沒有認證的接口,將會返回401,即沒有登錄,這時keycloak會將我們的請求重定向到keycloak的登錄而,這時有幾個參數將被發(fā)到keycloak服務端,用來獲取code信息。
主要包括以下幾個參數 :
Response_type:表示響應類型,這里我們是code
Client_id:表示為你這個客戶端頒發(fā)的唯一標識
Redirect_uri:表示從keycloak服務端注冊的合法的回調地址,支持通配符
Scope:表示認證范圍,表示用戶的openid方式,可以根據調用它需要,使用對應范圍的scope
- GET /auth/realms/demo/protocol/openid-connect/auth
- QUERY
client_id:democlient
scope:openid // 表示客戶端默認的權限范圍,當為客戶端配置了多個可選的范圍時,可以在這里指定你想要的權限范圍
response_type:code
client_secret:ec0fd1c6-68b0-4c39-a9fa-c3be25c8ef01
redirect_uri:http://localhost:9090/callback
- 跳轉到kc的登錄頁,完成用戶名和密碼的登錄

- 登錄成功之后,跳回callback刪除,在url參數上帶上了code

請求token
- POST /auth/realms/fabao/protocol/openid-connect/token
- 請求體 x-www-form-urlencoded
grant_type:authorization_code
code:68058719-add6-4b40-ab96-8e71af03827a.7a31b1a9-c3e8-46d4-b8cc-345012fcf4a2.25e52f60-5991-43dd-9108-873f60af385d
client_id:democlient
client_secret:ec0fd1c6-68b0-4c39-a9fa-c3be25c8ef01
redirect_uri:http://localhost:9090/callback
- 響應
{
"access_token": "xxx",
"expires_in": 3000,
"refresh_expires_in": 1800,
"refresh_token": "xxx",
"token_type": "bearer",
"id_token": "xxx",
"not-before-policy": 1619660302,
"session_state": "14812f50-b9f7-4cee-be56-bf9bef5c961a",
"scope": "openid roles email profile" // 我們獲取code時傳遞的scope是openid,它返回的scope是openid roles email profile,這說明roles email profile這三個是客戶端默認的授權范圍
}
客戶端授權范圍

三 JWT token解析
- PAYLOAD數據載體主要包括用戶ID,用戶名,用戶角色,過期時間等信息
- Sub:用戶ID
- preferred_username:賬號名稱
- Name:用戶姓名
- Email:電子郵件
- realm_access:領域角色
- resource_access:客戶端(資源服務)角色
- Azp:授權客戶端
- Typ:token的類型
- Aud:被授權的客戶端列表
- Exp:過期時間
- Iss: 當前領域的開放API
四 Scope對jwt的影響
我們可以配置域的scope,或者對指定的client配置 scope,如圖

圖中,我們把客戶端democlient的scope里的roles移除后,在返回的token里將不會出現和角色有關的信息,即realm_access和resource_access將被移除。

浙公網安備 33010602011771號