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

启用CSRF时Spring Security登出请求报403错误及疑问

问题说明

根据Spring Security官方文档,登出POST请求需携带CSRF token,但启用CSRF后调用/account/logout接口时出现403错误。通过配置csrf().ignoreAntMatchers("/account/logout")解决了问题,但疑惑为何忽略该路径即可正常工作。


相关配置

SecurityFilterChain 配置

public SecurityFilterChain securityFilterChain(
            HttpSecurity http,
            OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService,
            CustomOAuth2SuccessHandler customOAuth2SuccessHandler
    ) throws Exception {
        return http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                        .mvcMatchers(
                                ...
                                "/account/logout"
                        ).permitAll()
                        .mvcMatchers(
                                "/account/login",
                                ...
                        ).hasRole("ANONYMOUS")
                        ...
                )
                .csrf()
                    .ignoringAntMatchers("/account/logout")
                .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                ...
                .and()
                    .formLogin().disable()
                    .logout(logout -> logout
                            .logoutUrl("/account/logout")
                    )
                    .oauth2Login(oAuth -> oAuth
                            .loginPage("/account/login")
                            .userInfoEndpoint(userInfo -> userInfo
                                    .userService(oAuth2UserService))
                            .successHandler(customOAuth2SuccessHandler)
                    )
                    // 使用JWT token
                    .addFilterBefore(
                            new JwtTokenFilter(userAccountService, jwtProperties),
                            BasicAuthenticationFilter.class)
                    ...
    }

自定义登出端点

SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler();

@PostMapping("/account/logout")
public String requestLogout(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
        this.logoutHandler.logout(request, response, authentication);

        return "redirect:/";
    }

前端代码

<form id="logout" action="/account/logout" method="post">
    <button type="submit" class="btn text-success p-0">LogOut</button>
</form>

错误截图

错误截图1
错误截图2


问题原因分析

核心问题出在无状态会话配置和CSRF机制的依赖冲突:

  1. Spring Security的CSRF默认依赖HttpSession存储token,当你配置SessionCreationPolicy.STATELESS(无状态模式)时,服务器不会创建或维护Session,导致CSRF token无法被存储和读取。
  2. 你的前端表单没有携带CSRF token(比如Spring Security默认的_csrf隐藏域),但即使添加了这个隐藏域,后端因为没有Session,也无法验证token的有效性,仍然会返回403。
  3. 当配置csrf().ignoreAntMatchers("/account/logout")后,Spring Security会跳过对该接口的CSRF校验,所以请求能正常通过。

补充说明

在使用JWT的无状态应用中,CSRF的常规机制并不适用:

  • JWT本身是存储在客户端的凭证,CSRF攻击的前提是攻击者利用用户的服务器端会话凭证,而无状态模式下没有服务器端会话,CSRF风险大大降低。
  • 对于登出接口这类风险较低的操作,直接忽略CSRF校验是合理的做法;如果需要严格防护,可以考虑将CSRF token嵌入JWT中,但会增加复杂度,一般没必要。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:20:56