如何在Spring Security中让OidcUser同步KeyCloak用户资料变更?
解决KeyCloak用户资料更新后OidcUser数据不同步的问题
核心思路
默认的OidcUserService仅在首次认证时拉取用户信息,后续不会主动同步KeyCloak中的资料变更。要实现数据自动更新,需自定义OidcUserService,在每次认证(含令牌刷新流程)中主动调用OIDC的/userinfo端点,获取最新用户属性并更新OidcUser对象。
具体实现步骤
1. 自定义OidcUserService类
继承DefaultOidcUserService并重写loadUser方法,在原有逻辑基础上新增调用/userinfo端点的逻辑,用最新数据覆盖原有OidcUser属性:
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.oidc.OidcIdToken; import org.springframework.security.oauth2.core.oidc.OidcUserInfo; import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; import org.springframework.security.oauth2.core.oidc.user.OidcUser; public class CustomOidcUserService extends OidcUserService { @Override public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException { // 先通过默认逻辑获取基础OidcUser OidcUser originalUser = super.loadUser(userRequest); // 调用/userinfo端点拉取最新用户信息 OidcUserInfo latestUserInfo = this.retrieveUserInfo(userRequest); // 用最新信息重新构建OidcUser,覆盖原有属性 OidcIdToken idToken = originalUser.getIdToken(); return new DefaultOidcUser( originalUser.getAuthorities(), idToken, latestUserInfo, "name" // 指定映射姓名的字段,对应KeyCloak中的name属性 ); } }
2. 配置Spring Security替换默认服务
在Spring Security配置类中,将自定义的OidcUserService注入到OAuth2登录流程:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .oauth2Login(oauth2 -> oauth2 .userInfoEndpoint(userInfo -> userInfo .oidcUserService(customOidcUserService()) ) ); return http.build(); } @Bean public OidcUserService customOidcUserService() { return new CustomOidcUserService(); } }
3. 验证KeyCloak客户端配置
- 确保KeyCloak客户端已开启
openidscope,且userinfo端点可正常访问 - 客户端访问令牌需包含
profile、email等读取用户资料的权限(默认配置已包含)
额外优化
若对性能有要求,可给用户信息添加缓存逻辑,比如根据令牌过期时间缓存,避免每次请求都调用/userinfo端点;也可自定义属性映射规则,将KeyCloak中的locale等字段直接映射到OidcUser的对应属性。
内容的提问来源于stack exchange,提问作者Cesar Manuel Cruzata
相关产品推荐
相关产品推荐

