Spring Boot集成Keycloak仅获匿名令牌,如何获取登录用户名?
解决Keycloak保护Spring Boot REST API时获取当前用户名为
anonymousUser的问题 问题描述
此前使用标准用户详情服务完成用户认证,切换到Keycloak后,调用以下代码始终返回anonymousUser,且Spring Boot仅识别[ANONYMOUS_USER]角色:
public static String getCurrentUsername() { return (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); }
核心原因
Spring Security未正确拦截并解析Keycloak的认证令牌,导致请求被当作匿名请求处理。
正确配置步骤
1. 依赖配置(Maven)
确保引入匹配Spring Boot版本的Keycloak Starter依赖:
<dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-spring-boot-starter</artifactId> <version>${keycloak.version}</version> </dependency>
2. 应用配置(application.yml)
配置与Keycloak后台一致的客户端信息:
keycloak: auth-server-url: http://localhost:8080/auth realm: 你的领域名称 resource: 你的客户端ID credentials: secret: 你的客户端密钥 use-resource-role-mappings: true bearer-only: true ssl-required: external
bearer-only: true:服务端仅接受Bearer令牌,不做重定向认证use-resource-role-mappings: true:启用客户端角色映射
3. Spring Security配置类
创建配置类确保请求被Keycloak认证过滤器拦截:
import org.keycloak.adapters.springsecurity.KeycloakConfiguration; import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; @KeycloakConfiguration public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { KeycloakAuthenticationProvider authProvider = keycloakAuthenticationProvider(); // 可选:统一角色前缀,按需调整 authProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); auth.authenticationProvider(authProvider); } @Override protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { // REST API无需会话,使用空会话策略 return new NullAuthenticatedSessionStrategy(); } @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); http.csrf().disable() .authorizeRequests() // 配置需要认证的接口路径,替换为实际业务路径 .antMatchers("/api/**").authenticated() .anyRequest().permitAll(); } }
4. 调整用户名获取代码
原代码中getPrincipal()返回的是KeycloakAuthenticationToken对象,需调整逻辑提取用户名:
import org.keycloak.KeycloakPrincipal; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; public static String getCurrentUsername() { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (principal instanceof KeycloakAuthenticationToken) { KeycloakPrincipal<?> keycloakPrincipal = (KeycloakPrincipal<?>) ((KeycloakAuthenticationToken) principal).getPrincipal(); // 获取Keycloak用户的首选用户名 return keycloakPrincipal.getKeycloakSecurityContext().getToken().getPreferredUsername(); } // 兼容匿名或其他认证场景 return principal.toString(); }
关键检查项
- 确认请求头携带有效
Authorization: Bearer <token>令牌 - 用JWT工具解码令牌,验证包含
preferred_username字段 - 检查Keycloak客户端
Access Type是否设为confidential(使用客户端密钥时) - 确保Keycloak客户端已启用,且用户已分配对应客户端角色
内容的提问来源于stack exchange,提问作者jonathan-lee-devel
相关产品推荐
相关产品推荐

