Spring Boot集成Keycloak SSO时Principal对象为空问题求助
我之前也碰到过类似的问题,明明Keycloak日志显示认证成功了,但Spring控制器里就是拿不到Principal,给你几个靠谱的排查和解决方向:
1. 必须配置Spring Security的Keycloak适配类
Keycloak的Spring Boot Starter依赖Spring Security才能把认证信息绑定到Spring上下文里,你需要创建一个继承KeycloakWebSecurityConfigurerAdapter的配置类,确保认证流程被正确接入:
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 KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter { // 配置认证提供者,确保角色映射正确 @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { KeycloakAuthenticationProvider authProvider = keycloakAuthenticationProvider(); // 这里可以调整角色前缀,比如去掉默认的ROLE_,根据你的需求来 authProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); auth.authenticationProvider(authProvider); } // 配置会话策略,如果不需要session可以用Null策略 @Override protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { return new NullAuthenticatedSessionStrategy(); } // 配置Http安全规则,和你application.yml里的security-constraints对应上 @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); http.authorizeRequests() .antMatchers("/v2/auth/keycloak").hasRole("USER") .anyRequest().permitAll(); } }
2. 用@AuthenticationPrincipal直接注入KeycloakPrincipal
不要直接用Principal或者从HttpServletRequest里拿,试试Spring Security提供的@AuthenticationPrincipal注解,它能直接帮你注入认证后的KeycloakPrincipal对象:
import org.keycloak.KeycloakPrincipal; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @RestController public class AuthController { private static final Logger log = LoggerFactory.getLogger(AuthController.class); @GetMapping("/v2/auth/keycloak") public void authUsingKeycloak(@AuthenticationPrincipal KeycloakPrincipal<?> principal) { if (principal != null) { String username = principal.getName(); String userId = principal.getKeycloakSecurityContext().getToken().getSubject(); log.info("User {} (ID: {}) logged using Keycloak", username, userId); } else { log.warn("Principal is still null!"); } } }
3. 检查角色配置和版本兼容性
- 确认你的Keycloak用户确实被分配了
USER角色(不管是Realm级别还是Client级别,根据keycloak.use-resource-role-mappings的配置来),如果角色不匹配,认证后也可能无法正确绑定Principal。 - 检查Spring Boot和Keycloak版本的兼容性:你用的Keycloak 13.0.1对应的Spring Boot版本建议是2.4.x,如果你的Spring Boot版本太高(比如2.5+),可能需要调整Keycloak适配器的配置,或者升级Keycloak版本。
4. 排查是否有其他Security配置干扰
如果你还有其他自定义的Spring Security配置类,比如继承WebSecurityConfigurerAdapter的其他类,可能会覆盖Keycloak的配置,导致认证信息无法正确传递。确保只有一个Keycloak相关的Security配置类生效。
按照上面的步骤调整后,应该就能正确拿到Principal对象了。
内容的提问来源于stack exchange,提问作者Mithrand1r
相关产品推荐
相关产品推荐

