Keycloak 的簡單使用


1. 下載並安裝 Keycloak

2. 創建 Realm,Client,User

  • Keycloak 有一個默認的 Master Realm,自己再創建一個 Test Realm
  • 在 Test Realm 下創建一個命名為 resource_01 的 client
    • 進入 resource_01 的 Settings 頁,做以下配置

      (1) 將 Access Type 改為 confidential

      (2) 改為 confidential 后會多出 Authorization Enabled 選項,將其設置為 ON

      (3) Valid Redirect URIs 填 *
      配好后點擊 Save 保存
    • 進入 resource_01 的 Credentials 頁,記下 Secret 的值,后面訪問這個 client 的時候會用到
    • 進入 resource_01 的 Roles 頁,添加兩個 roles,分別命名為 admin 和 operator
  • 在 Test Realm 下創建一個 user_01 的 user
    • 進入 user_01 的 Credentials 頁,將 Temporary 設置為 OFF,然后重置密碼
  • 將 client 的 role 和 user 關聯
    • 進入 user_01 的 Role Mappings 頁,在 Client Roles 選 resource_01,在 Available Roles 選擇 admin,點 Add Selected,意味着 user_01 可以訪問 resource_01,並且是 admin 權限,可以再創建一個 user_02 將 role 選為 operator,意味着 user_02 可以訪問 resource_01,但只有做基本操作的權限(創建 client 的 role 的時候名字是可以隨便寫的,嚴格來講 resource_01,admin 和 operator 都是什么含義,應該由 server 決定)
  • client 的 role 也可以和其他 client 關聯 (這篇文章里沒用上)
    • 進入 client 的 Service Account Roles 頁,在 Client Roles -> Available Roles 選擇

3. 通過 Keycloak 做驗證

一般場景是三個節點:客戶端,服務端,Keycloak
客戶端通過 Keycloak 獲取一個 Token,再用這個 Token 訪問服務端,服務端對 Token 做驗證

這里用 Postman 模擬客戶端,假設要訪問的服務端的 URL 是 192.168.1.1:9090/api/server-name/v1/service-01

  1. 在 Authorization -> TYPE,選 OAuth 2.0
  2. 點 Get New Access Token,各項配置如下
    • Grant Type:Password Credentials
    • Access Token URL:http://localhost:8080/auth/realms/Test/protocol/openid-connect/token
    • Username:user_01
    • Password:user_01 的密碼
    • Client ID:resource_01
    • Client Secret:在 resource_01 的 Credentials 頁下找
    • Scope:Realm Setting -> General -> Endpoints 點 OpenID Endpoint Configurations 找到 scopes_supported 隨便選一個填比如 openid
    • Client Authentication :Send as Basic Auth Header (意思是 Postman 拿到 Token 后是放在 Header 發給服務端)

      點 Request Token,成功獲取后點 Use Token
  3. 發送請求給服務端

    實際上發送請求的時候,加上了一個 name 為 Authorization,value 為 Bearer ${token} 的 Header 項

以上操作用命令行執行的話命令如下

curl -k -X POST -d "grant_type=password&username=user_01&password=123456&scope=%22openid%22&client_id=resource_01&client_secret=d54d22b0-4941-415d-ba59-79b7ce70498e" http://localhost:8080/auth/realms/Test/protocol/openid-connect/token
curl -X GET -H "X-Request-With: XMLHttpRequest" -H "content-type: application/json" -H "Authorization: Bearer xxx" -H "api_key: queryOverdueInfo" http://192.168.1.1:9090/api/server-name/v1/service-01

4. Token 的內容

JWT (Json Web Token) 由三部分組成:header,payload,signature
從 Keycloak 獲取到的 token = base64(header) + "." + base64(payload) + "." + signature
其中 signature = encrypt( base64(header) + base64(payload) , privateKey)

可以看到,token 的 header 和 payload 相當於是明文的,只要對相應部分進行解碼就可以看到

服務器端主要用 publicKey 對 signature 部分解密,然后和 header,payload 部分對比,確保 token 是合法的

每一個 Realm 會有自己的 privateKey 和 publicKey

對 header 部分和 payload 部分解碼,內容如下

header

{
    "alg" : "RS256",
    "typ" : "JWT",
    "kid" : "jwQF3Y_V5vCfNSkKtP5XAt9LzdpKKjfjGOEFPZsw8xc"      // key id,密鑰 id
}

payload

{
	"jti":"df57c8b5-9801-47b3-9977-74a66e9a8d88",         // jwt id
	"exp":1580829682,                                     // 過期時間
	"nbf":0,                                              // 有效起始時間
	"iat":1580829382,                                     // 發行時間
	"iss":"http://localhost:8080/auth/realms/Test",       // 發行者
	"aud":"account",                                      // 受眾
	"sub":"0d61a540-4914-4887-ac28-87b21da91da3",         // 主題 
	"typ":"Bearer",
	"azp":"resource_01",                                  // Authorized party
	"auth_time":0,
	"session_state":"1a8a0680-5e6e-40dc-a150-9a84954dbc55",
	"acr":"1",
	"realm_access": {
		"roles":[
			"offline_access",
			"uma_authorization"
		]
	},
	"resource_access": {
		"resource_01": {
			"roles":[
				"admin"
			]
		},
		"account":{
			"roles":[
				"manage-account",
				"manage-account-links",
				"view-profile"
			]
		}
	},
	"scope":"openid email profile",
	"email_verified":false,
	"preferred_username":"user_01"
}

服務端驗證並解碼 token 就可以看到,這個 token 的 username 是 user_01,它有 resource_01 這個 client 的 admin 權限,服務端就可以根據 resource_01,admin 決定是否允許做相應的操作,當然也可以使用其它字段,這都是由服務端自己決定的

在請求 token 的時候,client id 不一定要填 user_01 關聯的 client,比如可以填上 resource_02 及相應的 secret,這也是允許的,這樣得到的 token,resource_access 部分依然是 resource_01 以及 admin(假設 user_01 沒有同時關聯 resource_02),但 azp 部分會變成 resource_02,這種用法的其中一種場景,是可以有一個統一的 client 做入口,比如有一個 client 就叫 resources,不論哪個 user 要訪問哪個 resource,獲取 token 的時候 client 都統一填 resources 就可以,因為 token 里的 resource_access 字段依然是 user 真正關聯的所有 client

如果請求 token 的時候,Grant Type 選的是 Client Credentials,這樣只需要填 client id 和 client secret,不需要填 user 和 password,這樣得到的 token,以 resource_01 為例子,會多一個 clientId 字段為 resource_01,而 preferred_username 部分將變成 service-account-resource_01,resource_access 部分還是 resource_01,roles 變成 uma_protection(這是創建 client 時默認就有的 role,如果把這個 role 刪除了,那么返回的 token 的 resource_access 字段不會有 resource_01 的信息)

5. Springboot 驗證 Token

如果服務端是 Springboot,那么有兩種方法驗證

  • 繼承 ResourceServerConfigurerAdapter 類,這是一個通用的做 OAUTH 2.0 驗證的類,驗證的 Token 可以不是 Keycloak 發的,只要是符合標准的 Token 就可以,需要配置包括 Realm 的 PublicKey 在內的一些信息,做驗證的時候 keycloak 可以沒運行,只要 PublicKey 能用於解密就可以

  • 繼承 KeycloakWebSecurityConfigurerAdapter 類,這是 springboot 做 keycloak 驗證的適配器,需要配 keycloak 的地址和相應的 Realm,不用配 PublicKey,springboot 自己會去拿,第一次驗證的時候 keycloak 必須在運行,后續的驗證不需要

6. 通過 REST API 操作 Keycloak

可用的 API:https://www.keycloak.org/docs-api/7.0/rest-api/index.html

要通過 API 操作,同樣需要通過 user 拿先一個 Token,再用這個 Token 去操作 Keycloak,這個 user 要有相應的權限

  1. 創建一個 user 命名為 admin_user
  2. 在 Role Mappings 的 Client Roles 選擇 realm-management,把 Available Roles 都加上
  3. 取 Token 的時候 client_id 填 admin-cli
  4. curl 命令如下
curl -k -X POST -d "grant_type=password&username=admin_user&password=123456&client_id=admin-cli" http://localhost:8080/auth/realms/Test/protocol/openid-connect/token



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM