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

Spring Security+Ajax:未认证Ajax请求如何返回401而非登录页?

绝对可以解决!我之前做项目的时候也遇到过这个坑——Spring Security默认会把所有未认证请求都重定向到登录页,这对AJAX请求来说完全不友好,前端拿到的是登录页的HTML代码,根本没法正常处理。不过我们可以通过自定义认证入口点来区分请求类型,分别处理。

具体实现步骤

1. 自定义AJAX感知的认证入口点

我们需要写一个AuthenticationEntryPoint的实现类,用来判断当前请求是否是AJAX请求:如果是,就返回401未授权状态码;如果不是,就走默认的重定向到登录页逻辑。

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

@Component
public class AjaxAwareAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private final AuthenticationEntryPoint defaultEntryPoint;

    // 注入Spring默认的登录入口点(比如LoginUrlAuthenticationEntryPoint)
    public AjaxAwareAuthenticationEntryPoint(AuthenticationEntryPoint defaultEntryPoint) {
        this.defaultEntryPoint = defaultEntryPoint;
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        // 检查请求头里的X-Requested-With,这是AJAX请求的常见标识
        if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授权,请重新登录");
        } else {
            // 非AJAX请求继续走默认的重定向逻辑
            defaultEntryPoint.commence(request, response, authException);
        }
    }
}

2. 在Spring Security配置中替换默认入口点

接下来在Security配置类里,把我们自定义的入口点设置进去,覆盖默认的异常处理逻辑:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final AjaxAwareAuthenticationEntryPoint ajaxAwareEntryPoint;

    public SecurityConfig(AjaxAwareAuthenticationEntryPoint ajaxAwareEntryPoint) {
        this.ajaxAwareEntryPoint = ajaxAwareEntryPoint;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated() // 所有请求都需要认证
            )
            .formLogin(form -> form
                .loginPage("/login") // 你的登录页路径
                .permitAll()
            )
            .exceptionHandling(ex -> ex
                .authenticationEntryPoint(ajaxAwareEntryPoint) // 启用自定义入口点
            );
        return http.build();
    }

    // 如果需要手动创建默认的登录入口点,添加这个Bean
    @Bean
    public AuthenticationEntryPoint defaultAuthenticationEntryPoint() {
        return new LoginUrlAuthenticationEntryPoint("/login");
    }
}

3. 额外优化建议

  • 适配现代前端框架:有些现代前端框架(比如React、Vue3)默认不会携带X-Requested-With头,这时候你可以在前端请求拦截器里手动添加,或者修改后端的判断逻辑,比如检查请求的Accept头是否包含application/json:
    if (request.getHeader("Accept") != null && request.getHeader("Accept").contains("application/json")) {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授权");
    }
    
  • 前端配合处理:后端返回401后,前端要在响应拦截器里捕获这个状态码,跳转到登录页或者弹出登录模态框,这样用户体验才完整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:51:22