• 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
    


  • 相关阅读:
    HTML 5 使用 FileReader、FormData实现文件上传
    【JS深入学习】——事件代理/事件委托
    【JS深入学习】——函数创建和重载
    Yii
    YII简单的基于角色的访问控制
    怎样在Yii中显示静态页
    Yii framework 应用总结小窍门(转)
    Yii PHP 框架分析(四)
    Yii PHP 框架分析(三)
    Yii PHP 框架分析(二)
  • 原文地址:https://www.cnblogs.com/moonlight-lin/p/12264142.html
Copyright © 2020-2023  润新知