Keycloak令牌访问REST API遇403,求错误排查及传递方法
咱们先理清你遇到的两个核心问题:令牌传递方式错误,以及Jetty安全约束的角色配置逻辑理解偏差,这两个点共同导致了403 !role 错误。
1. 令牌传递方式完全不符合规范
你当前用URL参数code=generated_code传递令牌的方式,完全不符合OAuth2/OpenID Connect的访问令牌使用规则,Keycloak Jetty适配器默认根本不会解析这种形式的令牌。
正确的做法是把访问令牌放在HTTP请求的Authorization请求头中,格式固定为:
Authorization: Bearer <你的访问令牌字符串>
举个curl请求的示例,你可以参考:
curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6IC..." http://localhost:7100/api/v1/test
你之前用的code参数是OAuth2授权码流程里的临时授权码,不是访问令牌,适配器自然无法识别并验证它——这是第一个关键错误。
2. Jetty安全约束的角色配置逻辑错配
你在代码里设置了constraint.setRoles(new String[]{"*"}),这里的*在Jetty的Constraint中并不是“允许所有已认证用户”的意思,反而会被Keycloak适配器理解为要求用户必须拥有名为*的实际角色,但你的用户令牌里肯定没有这个不存在的角色,所以直接返回了!role的403错误。
如果你的需求是“允许所有已通过认证的用户访问资源”,正确的配置方式是:
Constraint constraint = new Constraint(); constraint.setAuthenticate(true); // 设置为空数组,表示只要求用户完成认证,不检查具体角色 constraint.setRoles(new String[]{}); // 也可以直接用Jetty内置的常量:constraint.setRoles(Constraint.__NO_ROLES); constraintMapping.setConstraint(constraint);
如果需要基于具体角色做访问控制,那就要确保配置里的角色名称和Keycloak后台给用户分配的角色完全一致,比如用户拥有api_user角色,就设置constraint.setRoles(new String[]{"api_user"})。
3. 额外的验证检查点
虽然你说两个应用的Keycloak配置完全一致,还是建议你确认以下两点:
- 用本地工具(比如jwt.io,无需上传令牌到第三方)解析第一个应用生成的令牌,确认令牌里的
realm_access.roles或resource_access.my_resource.roles(对应你配置的resource名称)包含正确的角色信息。 - 核对第二个应用
AdapterConfig里的resource名称、credentials.secret和Keycloak后台客户端配置完全一致,避免拼写或字符遗漏的问题。
内容的提问来源于stack exchange,提问作者tryingToLearn

