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

Spring Boot多租户集成Keycloak登录后陷入无限重定向循环

Spring Boot多租户应用Keycloak登录后无限重定向问题

问题现象

Spring Boot多租户集成Keycloak认证时,Keycloak端登录验证通过,但重定向回应用后陷入无限重定向循环。调试确认访问Keycloak时使用的租户与Realm均正确,浏览器网络日志显示持续重复重定向操作。

相关代码配置

SecurityConfig 安全配置

@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http, ClientRegistrationRepository clients) throws Exception {
        http.
                authorizeHttpRequests(auth -> auth
                        .requestMatchers("/", "/webjars/**", "/js/**", "/images/**", "/actuator/**", "/login").permitAll()
                        .anyRequest().authenticated()
                )
                .oauth2Login(oath2 -> oath2
                        .clientRegistrationRepository(clients)
                        .loginPage("/login")
                        .defaultSuccessUrl("/home", false)
                )
                .logout(logout -> logout
                        .logoutSuccessHandler(tenantLogoutHandler())
                        .logoutSuccessUrl("/")
                        .invalidateHttpSession(true)
                        .clearAuthentication(true)
                        .deleteCookies("JSESSIONID")
                );

        return http.build();
    }

    @Bean
    LogoutSuccessHandler tenantLogoutHandler() {
        return ((request, response, authentication) -> {
            String t = TenantContext.getTenant();
            String logoutUrl = String.format(
                    "http://localhost:8081/realms/%s/protocol/openid-connect/logout?redirect_uri=http://%s:8080/",
                    t, t + ".localhost"
            );
            response.sendRedirect(logoutUrl);
        });
    }
}

LoginController 登录控制器

@Controller
class LoginController {
    @GetMapping("/login")
    public String login() {
        String tenant = TenantContext.getTenant();
        return "redirect:/oauth2/authorization/" + tenant;
    }
}

问题排查与解决方案

1. 放行OAuth2回调端点

当前安全配置未放行OAuth2回调路径/login/oauth2/code/**,导致回调请求被认证过滤器拦截,触发重定向到/login,形成循环。需将该路径加入permitAll列表:

.authorizeHttpRequests(auth -> auth
        .requestMatchers("/", "/webjars/**", "/js/**", "/images/**", "/actuator/**", "/login", "/login/oauth2/code/**").permitAll()
        .anyRequest().authenticated()
)

2. 确保租户上下文在回调阶段可用

重定向回调时,TenantContext可能未正确设置,导致LoginController重复触发授权跳转。需在请求进入Spring Security前解析租户并设置上下文,例如添加租户解析过滤器:

@Component
public class TenantFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String host = req.getServerName();
        // 从域名提取租户标识,如`tenant.localhost`提取`tenant`
        String tenant = host.split("\\.")[0];
        TenantContext.setTenant(tenant);
        try {
            chain.doFilter(request, response);
        } finally {
            // 请求结束后清理上下文,避免线程污染
            TenantContext.clearTenant();
        }
    }
}

并确保该过滤器在Spring Security过滤器链之前执行。

3. 验证defaultSuccessUrl配置

确认defaultSuccessUrl("/home", false)的参数逻辑:第二个参数设为false表示仅在登录成功后首次跳转时使用该URL,若用户直接访问受保护资源,登录后会跳转到原资源路径。若业务需要强制跳转首页,可改为true,但此配置并非当前循环的核心原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 01:27:14