You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Keycloak与Angular+REST集成疑问及角色为空问题排查

关于Keycloak与Angular+Spring Boot集成的两个问题解答

一、双客户端方案是否为最优?能否用单个机密客户端适配前后端?

首先明确:双客户端方案是Keycloak针对SPA+后端API场景的推荐最佳实践,绝对不建议用单个机密客户端同时适配前后端,核心原因如下:

  • Angular作为单页应用(SPA)属于公开客户端,它运行在浏览器环境中,根本无法安全存储机密客户端的密钥——任何嵌入在前端代码里的密钥,都能通过浏览器开发者工具、反编译等方式被轻易获取,这会直接导致你的客户端身份被冒充,带来严重的安全风险。
  • 双客户端的分工更清晰合理:
    • 公开客户端(frontend-dev):专门负责前端认证流程,处理OIDC授权码流程(配合PKCE防止授权码劫持),不需要密钥,完全适配浏览器的安全环境。
    • Bearer-only客户端(backend-dev):专门用于后端API的令牌校验,只接受JWT令牌并验证其合法性,不需要处理前端登录跳转,用密钥确保只有合法的令牌来源能通过校验。

强行用单个机密客户端适配前后端,完全违背了OAuth2/OIDC的安全设计原则,属于典型的不安全实践。


二、后端Spring Boot无法获取角色导致403的问题排查与解决

结合你提供的配置和环境(Keycloak 3.4.12、Spring Boot 1.5.18、Keycloak Spring Adapter 3.4.3),出现@RolesAllowed失效、角色为空的情况,大概率是以下几个原因:

1. 角色映射与权限前缀不匹配

你配置了SimpleAuthorityMapper,这个类默认会把Keycloak返回的角色名转换为大写并添加ROLE_前缀。比如:

  • 如果Keycloak中给用户分配的客户端角色是admin,Spring Security中实际生成的权限会是ROLE_ADMIN。
  • 但如果你代码中用的是@RolesAllowed("admin"),就会因为权限不匹配返回403。

解决方法:
要么把注解改成@RolesAllowed("ROLE_ADMIN"),要么调整SimpleAuthorityMapper的配置,取消前缀或关闭大写转换:

keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper() {{
    setPrefix(""); // 去掉ROLE_前缀
    setConvertToUpperCase(false); // 不强制转换为大写
}});

2. 未正确使用客户端角色映射

你设置了keycloak.use-resource-role-mappings=true,这意味着Spring Security只会读取当前客户端(backend-dev)的角色,而不是Realm级别的角色。请确认:

  • 你给用户分配的是backend-dev客户端下的角色,而非Realm角色。
  • 在Keycloak控制台的backend-dev客户端设置中,检查Scope标签页,确保需要的角色被包含在客户端可用范围内(或者直接开启Full Scope Allowed)。

3. JWT令牌中未包含客户端角色

可以用jwt.io解析前端传递给后端的Bearer令牌,查看resource_access字段是否包含backend-dev的角色信息,正确的结构应该是:

"resource_access": {
  "backend-dev": {
    "roles": ["admin", "user"]
  }
}

如果没有这个结构,说明Keycloak没有将客户端角色注入到令牌中,需要检查:

  • 用户是否确实被分配了backend-dev的角色。
  • backend-dev客户端的Settings标签页中,Access Type是否设置为bearer-only(你的配置是对的,但需要确认控制台设置一致)。

4. Keycloak适配器与Server版本不兼容

你使用的Keycloak Server是3.4.12,但Spring Adapter是3.4.3,版本差异较大,很可能存在兼容性问题。Keycloak的适配器版本建议与Server版本完全一致,否则容易出现令牌解析、角色映射等异常。

解决方法:将Spring Boot的Keycloak依赖版本升级到3.4.12,比如在pom.xml中:

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-spring-boot-starter</artifactId>
    <version>3.4.12.Final</version>
</dependency>

5. 手动获取角色的方式错误

你当前手动获取角色的代码是从AccessToken中读取,但开启use-resource-role-mappings=true后,应该读取resourceAccess中的客户端角色,而非realmAccess。正确的获取方式示例:

AccessToken token = ((KeycloakSecurityContext)((KeycloakAuthenticationToken) request.getUserPrincipal()).getCredentials()).getToken();
// 获取backend-dev客户端的角色列表
List<String> clientRoles = token.getResourceAccess("backend-dev").getRoles();

如果你之前读取的是token.getRealmAccess().getRoles(),那自然会得到空数组,因为你设置了只使用客户端角色映射。


内容的提问来源于stack exchange,提问作者aquero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:58:48