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

如何通过Spring Boot将Keycloak用户同步至MongoDB并获取用户ID?

Keycloak用户同步到MongoDB的实现方案

一、实时同步:Keycloak事件监听(推荐)

Keycloak自带事件监听机制,用户注册、更新时会触发对应事件,你可以自定义监听器把用户数据推送到Spring Boot服务,再写入MongoDB。

实现步骤:

  1. 自定义Keycloak事件监听器
    编写实现EventListenerProvider的Java类,监听REGISTER事件,提取用户的Keycloak ID、用户名、邮箱等信息,通过HTTP调用Spring Boot同步接口:

    public class CustomUserEventListener implements EventListenerProvider {
        private final HttpClient httpClient;
        private final String syncApiUrl;
    
        @Override
        public void onEvent(Event event) {
            if (EventType.REGISTER.equals(event.getType())) {
                UserModel user = session.users().getUserById(event.getUserId(), session.getContext().getRealm());
                UserSyncDto dto = new UserSyncDto();
                dto.setKeycloakId(user.getId());
                dto.setUsername(user.getUsername());
                dto.setEmail(user.getEmail());
                // 调用Spring Boot同步接口
                httpClient.post(syncApiUrl, dto);
            }
        }
        // 其他接口实现逻辑...
    }
    

    把这个类打包成JAR放到Keycloak的providers目录,再在Keycloak后台启用该监听器。

  2. Spring Boot接收同步请求
    写一个REST接口,接收Keycloak传来的用户数据,检查MongoDB中是否存在该Keycloak ID,不存在则创建新的User文档:

    @RestController
    @RequestMapping("/api/user-sync")
    public class UserSyncController {
        private final UserRepository userRepository;
    
        @PostMapping
        public ResponseEntity<Void> syncUser(@RequestBody UserSyncDto dto) {
            if (!userRepository.existsByKeycloakId(dto.getKeycloakId())) {
                User user = new User();
                user.setKeycloakId(dto.getKeycloakId());
                user.setUsername(dto.getUsername());
                user.setEmail(dto.getEmail());
                userRepository.save(user);
            }
            return ResponseEntity.ok().build();
        }
    }
    

二、按需同步:Spring Security认证时自动创建

用户首次通过Keycloak认证访问资源服务器时,从JWT令牌中提取Keycloak用户ID,检查MongoDB中是否存在该用户,不存在则自动创建文档。

实现步骤:

  1. 配置Spring Security提取JWT信息
    在资源服务器配置中启用JWT认证:

    @Configuration
    @EnableResourceServer
    public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2ResourceServer().jwt();
        }
    }
    
  2. 拦截认证请求同步用户
    通过@RestControllerAdvice拦截认证后的请求,提取并同步用户信息:

    @RestControllerAdvice
    public class UserSyncAdvice {
        private final UserRepository userRepository;
    
        @ModelAttribute
        public void syncCurrentUser(Authentication authentication) {
            if (authentication instanceof JwtAuthenticationToken) {
                Jwt jwt = ((JwtAuthenticationToken) authentication).getToken();
                String keycloakId = jwt.getSubject();
                String username = jwt.getClaimAsString("preferred_username");
                String email = jwt.getClaimAsString("email");
    
                userRepository.findByKeycloakId(keycloakId)
                    .orElseGet(() -> {
                        User user = new User();
                        user.setKeycloakId(keycloakId);
                        user.setUsername(username);
                        user.setEmail(email);
                        return userRepository.save(user);
                    });
            }
        }
    }
    

    这种方式无需修改Keycloak,适合用户首次访问时自动初始化数据,缺点是用户不访问服务则不会同步数据。

三、定时同步:Keycloak Admin API批量拉取

如果需要同步历史用户或补全数据,可以用Keycloak Admin API定时拉取用户列表,对比MongoDB数据做更新或插入。

实现步骤:

  1. 添加Keycloak Admin依赖
    在Spring Boot的pom.xml中引入官方客户端:

    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-admin-client</artifactId>
        <version>${keycloak.version}</version>
    </dependency>
    
  2. 编写定时同步任务
    使用Spring的@Scheduled注解定期调用Admin API拉取用户:

    @Service
    public class UserSyncService {
        private final Keycloak keycloak;
        private final UserRepository userRepository;
    
        @Scheduled(fixedRate = 3600000) // 每小时同步一次
        public void syncUsers() {
            List<UserRepresentation> keycloakUsers = keycloak.realm("your-realm")
                .users()
                .list();
    
            for (UserRepresentation kcUser : keycloakUsers) {
                userRepository.findByKeycloakId(kcUser.getId())
                    .ifPresentOrElse(
                        existingUser -> {
                            // 更新已有用户信息
                            existingUser.setUsername(kcUser.getUsername());
                            existingUser.setEmail(kcUser.getEmail());
                            userRepository.save(existingUser);
                        },
                        () -> {
                            // 创建新用户
                            User user = new User();
                            user.setKeycloakId(kcUser.getId());
                            user.setUsername(kcUser.getUsername());
                            user.setEmail(kcUser.getEmail());
                            userRepository.save(user);
                        }
                    );
            }
        }
    }
    

    注意要在Keycloak后台创建一个拥有用户查询权限的服务账号,用于Admin API的身份认证。

四、可用工具/库

  • Keycloak Event Listeners:官方原生扩展机制,无需额外依赖,定制性强。
  • Keycloak Admin Client:官方提供的Java客户端,方便调用Admin API实现批量同步。
  • Spring Security OAuth2 Resource Server:配合JWT自动提取用户信息,实现按需同步,无需额外工具。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 14:35:18