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

JHipster7.8+Keycloak+React用户注册/登录无限重定向问题求助

问题分析与解决方案

问题现象

基于JHipster 7.8、Spring、React、Keycloak构建的应用,出现以下异常:

  • 新用户注册时,调试模式下UserService.syncUserWithIdP方法被持续调用,浏览器在localhost:9000和localhost:9000/oauth2/authorization/oidc之间无限重定向,最终跳转到http://localhost:9000/login?error。
  • 调用MyCustomSupplierRepository.save(supplier)保存用户额外数据时,登录环节也会触发相同错误。

核心原因排查

从提供的UserService.java代码中,定位到几个关键问题:

1. syncUserWithIdP中用户更新逻辑的缺陷

updateUser方法依赖SecurityUtils.getCurrentUserLogin()获取当前登录用户,但在用户同步阶段(syncUserWithIdP执行时),用户尚未完成完整认证流程,SecurityUtils.getCurrentUserLogin()会返回空值,导致用户数据更新失败。后续认证流程会认为用户数据未同步完成,反复触发syncUserWithIdP,最终引发重定向循环。

2. 用户权限为空的处理逻辑缺失

在getUserFromAuthentication方法中,当用户没有权限时,代码创建了USER权限,但未将其添加到用户的权限集合中,导致用户权限始终为空。Spring Security判定用户未通过认证,触发重定向到授权服务器,形成循环。

3. Supplier保存时的关联关系问题

fillSupplierWithNewData方法中设置了supplier.setUser(user),如果Supplier与User的关联配置(如级联操作、事务传播)不合理,保存Supplier时可能导致User数据状态不一致,进而触发认证时的反复同步。

修复方案

1. 重构syncUserWithIdP中的用户更新逻辑

直接操作已查询到的existingUser对象,替代依赖当前登录用户的updateUser方法:

// 替换syncUserWithIdP中更新用户的代码段
if (existingUser.isPresent()) {
    User dbUser = existingUser.get();
    boolean needUpdate = false;
    // 判断是否需要更新用户数据
    if (details.get("updated_at") != null) {
        Instant dbModifiedDate = dbUser.getLastModifiedDate();
        Instant idpModifiedDate = (Instant) details.get("updated_at");
        needUpdate = idpModifiedDate.isAfter(dbModifiedDate);
    } else {
        needUpdate = true;
    }
    if (needUpdate) {
        log.debug("Updating user '{}' in local database", user.getLogin());
        dbUser.setFirstName(user.getFirstName());
        dbUser.setLastName(user.getLastName());
        if (user.getEmail() != null) {
            dbUser.setEmail(user.getEmail().toLowerCase());
        }
        dbUser.setLangKey(user.getLangKey());
        dbUser.setImageUrl(user.getImageUrl());
        this.clearUserCaches(dbUser);
        // 无需额外调用save,@Transactional会自动提交修改
    }
} else {
    // 原新用户保存逻辑保持不变
    log.debug("Saving user '{}' in local database", user.getLogin());
    user = userRepository.save(user);
    this.clearUserCaches(user);
}

2. 修复权限为空的处理逻辑

将创建的USER权限添加到用户的权限集合中:

// 修改getUserFromAuthentication中的权限处理代码
if (user.getAuthorities() == null || user.getAuthorities().size() == 0) {
    Authority auth = new Authority();
    auth.setName(AuthoritiesConstants.USER);
    user.getAuthorities().add(auth); // 新增此行,将权限添加到用户集合
}

3. 优化Supplier与User的关联配置

  • 确保Supplier实体中user字段的关联注解配置正确:
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;
    
  • 在调用supplierExtendedRepository.save(supplier)的方法上添加@Transactional注解,确保事务覆盖User和Supplier的操作,避免数据不一致。

验证步骤

  1. 重启应用,注册新用户,观察是否还会出现无限重定向。
  2. 保存用户的Supplier数据后,尝试登录,检查认证流程是否正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 00:56:07