使用gocloak中Login()返回的Access Token无法在Keycloak创建新Client的原因排查
Why does gocloak.Login() return an access token that fails to create a Keycloak Client (403 Forbidden)?
这是因为gocloak.Login()和gocloak.LoginAdmin()获取的Access Token权限完全不同,前者的权限不足以执行创建Client的操作,后者拥有管理员级别的权限,具体差异如下:
1. 两个登录方法的身份本质不同
gocloak.Login()采用的是客户端凭证流(Client Credentials Flow):你传入的"my-go-service"是一个Keycloak客户端ID,"vizhhp0qnDGaiq4k0aOzzn4RaaqSwU2b"是这个客户端的密钥,它代表的是客户端本身的身份,而不是一个具备管理权限的用户。gocloak.LoginAdmin()采用的是密码流(Password Flow):你传入的"admin"是Keycloak的管理员用户账号,获取的Token代表的是管理员用户身份,默认拥有对Realm的全量管理权限。
2. Keycloak的权限控制逻辑限制
创建Client属于Realm级别的管理操作,需要对应的权限(比如manage-clients角色):
- 用
Login()获取的Token,默认情况下"my-go-service"这个客户端并没有被授予demorealm的管理权限,所以Keycloak会拒绝这个操作,返回403 Forbidden。 - 用
LoginAdmin()获取的Token,管理员用户默认拥有Realm的所有管理权限,包括创建Client的权限,因此可以成功执行操作。
如果你想通过Login()实现创建Client的操作
如果确实需要用客户端身份来执行这个管理操作,可以按照以下步骤配置:
- 在Keycloak控制台中,进入
masterRealm(你的my-go-service客户端所在的Realm),找到这个客户端。 - 开启Service Accounts Enabled选项,然后切换到「Service Account Roles」标签页。
- 在「Client Roles」下拉框中选择
demorealm,然后将manage-clients等必要的管理角色添加到这个客户端的服务账户中。 - 确保客户端的Access Type设置为
confidential(因为需要使用密钥进行凭证登录)。
你的代码示例
func main() { newClientID := "new_client" client := gocloak.NewClient("http://localhost:8080") // Login()返回的Access Token导致403错误 jwt, _ := client.Login(context.Background(), "my-go-service", "vizhhp0qnDGaiq4k0aOzzn4RaaqSwU2b", "master", "admin", "Pa55w0rd") _, err := client.CreateClient(context.Background(), jwt.AccessToken, "demorealm", gocloak.Client{ ClientID: &newClientID}) if err != nil { fmt.Println(err.Error()) } // LoginAdmin()返回的Access Token可正常工作 jwt, _ = client.LoginAdmin(context.Background(), "admin", "Pa55w0rd", "master") clientID, err := client.CreateClient(context.Background(), jwt.AccessToken, "demorealm", gocloak.Client{ ClientID: &newClientID}) if err != nil { fmt.Println(err.Error()) } else { fmt.Printf("Client %s created", clientID) } }
执行结果
403 Forbidden: unknown_error Client d869fd8d-e5f0-4567-99de-69ccc4403705 created
内容的提问来源于stack exchange,提问作者Lương Nguyễn Trọng Duc




