Keycloak集成Google登录后基于角色的访问控制失效问题
解决方案:Keycloak + Spring Boot Google登录角色权限配置
一、Keycloak端正确配置角色与JWT映射
1. 创建Realm角色
- 进入
google-testeRealm → Roles → Add role - 创建
user和admin两个Realm角色并保存。
2. 设置默认角色(自动赋予所有新用户)
- 在Realm的Roles → Default Roles
- 将
user角色添加到Default Roles列表,保存后所有通过Google登录的新用户会自动获得user角色。
3. 确保客户端包含角色Scope并正确映射
- 进入客户端
spring-security-keycloak→ Client scopes - 确认
roles默认Client Scope已添加到Assigned client scopes - 点击
rolesScope → Mappers → 找到realm roles映射器:- 开启Enabled状态
- 确认Token Claim Name为
realm_access.roles - Claim JSON Type设为
String,Multivalued设为On - Role prefix留空,保存设置。
4. 手动为用户分配Admin角色
- 进入Realm的Users → 通过
preferred_username找到Google登录的用户 - 进入用户详情 → Role mappings
- 在Available roles中选择
admin,添加到Assigned roles并保存。
二、Spring Boot端调整权限配置
1. 自定义JWT权限转换器(处理角色前缀)
Spring Security的hasRole()会自动添加ROLE_前缀,需将Keycloak返回的纯角色名转换为对应格式:
import org.springframework.core.convert.converter.Converter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.jwt.Jwt; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; public class KeycloakJwtGrantedAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> { @Override public Collection<GrantedAuthority> convert(Jwt jwt) { List<String> roles = jwt.getClaimAsList("realm_access.roles"); return roles == null ? List.of() : roles.stream() .map(role -> new SimpleGrantedAuthority("ROLE_" + role)) .collect(Collectors.toList()); } }
2. 更新SecurityConfig配置
将自定义转换器加入OAuth2资源服务器的JWT配置:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(authorizeConfig -> { authorizeConfig.requestMatchers("/public", "/logout").permitAll(); authorizeConfig.requestMatchers("/admin").hasRole("admin"); authorizeConfig.requestMatchers("/usuario").hasRole("user"); authorizeConfig.anyRequest().authenticated(); }) .oauth2Login(Customizer.withDefaults()) .oauth2ResourceServer(config -> { config.jwt(jwtConfig -> { jwtConfig.jwtAuthenticationConverter(jwtAuthenticationConverter()); }); }) .build(); } @Bean JwtAuthenticationConverter jwtAuthenticationConverter() { JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(new KeycloakJwtGrantedAuthoritiesConverter()); return converter; } }
可选方案:使用hasAuthority替代hasRole
若不想自定义转换器,可直接修改权限判断逻辑,将hasRole("admin")改为hasAuthority("admin"),hasRole("user")改为hasAuthority("user"),直接匹配Keycloak返回的角色名称。
三、验证配置
- 重启Spring Boot与Keycloak服务
- Google登录后访问
/cookie接口,检查Authorities是否包含对应权限 - 查看JWT内容,确认
realm_access.roles中包含user(所有用户)和admin(已分配用户) - 测试路由:普通用户可访问
/usuario,无法访问/admin;admin用户可访问两个路由。
内容的提问来源于stack exchange,提问作者PauloRamos
相关产品推荐
相关产品推荐

