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

Spring Security登出重定向外部认证服务器时的CORS问题

我来帮你解决这个Azure B2C登出的CORS问题,核心原因是你当前的配置让前端AJAX请求直接去调用Azure的logout端点,而这个端点是设计给浏览器导航用的,不支持带自定义头(比如你的X-XSRF-TOKEN)的跨域AJAX请求。下面是纯Spring端的解决方案:


问题根源分析

你的前端用fetch发起登出请求后,Spring配置的logoutSuccessUrl会让前端收到302重定向,随后fetch会自动跟进去请求Azure的logout端点——这时候是跨域AJAX请求,还带了X-XSRF-TOKEN头。Azure B2C的logout端点虽然通过了预检请求,但实际响应没有返回Access-Control-Allow-Origin头,导致浏览器触发CORS报错。

纯Spring端解决方案

我们需要修改Spring Security的登出逻辑:先完成Spring端的会话清除,然后让浏览器直接导航到Azure的logout端点(而非让AJAX请求去调用),这样就不会触发CORS检查。

1. 自定义登出成功处理器

创建一个LogoutSuccessHandler的实现类,负责清除本地会话、构造Azure的登出URL,然后返回让浏览器跳转的响应:

import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AzureB2CLogoutSuccessHandler implements LogoutSuccessHandler {

    private final String tenant;
    private final String policy;
    private final String postLogoutRedirectUri;

    // 构造函数注入配置参数
    public AzureB2CLogoutSuccessHandler(String tenant, String policy, String postLogoutRedirectUri) {
        this.tenant = tenant;
        this.policy = policy;
        this.postLogoutRedirectUri = postLogoutRedirectUri;
    }

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        // 1. 清除Spring端的会话和Security上下文
        request.getSession().invalidate();

        // 2. 构造Azure B2C的登出URL(替换成你的实际参数)
        String azureLogoutUrl = String.format(
            "https://%s.b2clogin.com/%s.onmicrosoft.com/%s/oauth2/v2.0/logout?post_logout_redirect_uri=%s",
            tenant, tenant, policy, postLogoutRedirectUri
        );

        // 3. 返回HTML响应,用JS强制浏览器跳转(兼容AJAX请求场景)
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write(String.format("""
            <!DOCTYPE html>
            <html>
                <body>
                    <script>
                        window.location.href = "%s";
                    </script>
                    Logging out... If not redirected automatically, <a href="%s">click here</a>.
                </body>
            </html>
            """, azureLogoutUrl, azureLogoutUrl));
    }
}

2. 修改Spring Security配置

替换原来的logoutSuccessUrl配置,改用自定义的处理器:

@Override
protected void configure(HttpSecurity http) throws Exception {
    OidcUserService oidcUserService = new OidcUserService();

    // 初始化自定义登出处理器,替换为你的实际租户、策略和URL编码后的重定向URI
    AzureB2CLogoutSuccessHandler logoutHandler = new AzureB2CLogoutSuccessHandler(
        "your-tenant-id",
        "your-signup-signin-policy",
        "https%3A%2F%2Fjwt.ms%2F"
    );

    http
        .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
        .and()
        .requestMatchers()
            .antMatchers("/camunda/**", "/api/**", "/login/**", "/oauth2/**")
        .and()
        .authorizeRequests()
            .anyRequest().authenticated()
        .and()
        .oauth2Login()
            .loginPage("/oauth2/authorization/azure-ac")
            .userInfoEndpoint().oidcUserService(oidcUserService)
        .and()
        .logout()
            .logoutUrl("/camunda/api/admin/auth/user/default/logout")
            .logoutSuccessHandler(logoutHandler) // 使用自定义处理器替代logoutSuccessUrl
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID", "XSRF-TOKEN"); // 清除相关Cookie
}

关键说明

  • 为什么这样能解决CORS问题?因为我们不再让前端AJAX直接请求Azure的端点,而是让浏览器通过JS执行页面导航——这是正常的浏览器跳转行为,不会触发跨域AJAX的CORS检查。
  • 请确保你的post_logout_redirect_uri已经在Azure B2C的应用注册中添加为允许的重定向URI,否则Azure会拒绝跳转。
  • 自定义处理器同时兼容了普通导航请求和AJAX请求场景,即使前端是第三方无法修改,也能自动触发跳转。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:29:11