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

Spring Security每次Axios请求均重定向至登录页返回302问题

Axios请求返回302重定向至登录页的解决方案

核心问题分析

  1. 表单登录默认行为触发重定向:你的Spring Security配置启用了formLogin(Customizer.withDefaults()),当/api/**接口认证失败时,框架会默认返回302重定向到登录页,这是表单登录的内置逻辑,和你使用的JWT无状态认证不兼容。
  2. 会话策略不匹配:当前设置SessionCreationPolicy.ALWAYS,而JWT认证不需要服务器维护会话,应该使用无状态策略。
  3. 认证失败未自定义响应:没有配置JWT认证失败的专属处理逻辑,导致默认走表单登录的重定向流程。

具体修复步骤

1. 修改Spring Security配置,适配JWT认证

禁用表单登录和HTTP Basic认证,设置无状态会话策略,并自定义认证失败/权限不足的JSON响应:

@Bean 
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception{

    http.securityContext(context -> context.requireExplicitSave(false)) 
        // 改为无状态会话,适配JWT认证
        .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) 
        .cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource(){ 
            @Override 
            public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { 
                CorsConfiguration config = new CorsConfiguration(); 
                config.setAllowedOrigins(Collections.singletonList("http://localhost:5173")); 
                config.setAllowedHeaders(Collections.singletonList("*")); 
                config.setAllowedMethods(Collections.singletonList("*")); 
                config.setAllowCredentials(true); 
                config.setMaxAge(3600L);
                config.setExposedHeaders(List.of("Authorization")); 
                return config; 
            } 
        })) 
        .csrf(AbstractHttpConfigurer::disable) 
        .authorizeHttpRequests(request -> request
            .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() 
            .requestMatchers(HttpMethod.GET, "/basicAuth/**").permitAll() 
            .requestMatchers(HttpMethod.POST, "/register").permitAll() 
            .requestMatchers(HttpMethod.GET, "/").permitAll() 
            .requestMatchers("/admin/**").hasRole("ADMIN") 
            .requestMatchers("/api/**").authenticated() 
        ) 
        .addFilterBefore(new JWTTokenValidatorFilter(), BasicAuthenticationFilter.class) 
        .addFilterAfter(new JWTTokenGeneratorFilter(), BasicAuthenticationFilter.class)
        // 禁用表单登录和HTTP Basic认证
        .formLogin(AbstractHttpConfigurer::disable)
        .httpBasic(AbstractHttpConfigurer::disable)
        // 自定义认证异常处理,返回401/403 JSON响应
        .exceptionHandling(exceptions -> exceptions
            .authenticationEntryPoint((request, response, authException) -> {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                String json = "{\"error\": \"Unauthorized\", \"message\": \"无效或缺失Token\"}";
                response.getWriter().write(json);
            })
            .accessDeniedHandler((request, response, accessDeniedException) -> {
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                String json = "{\"error\": \"Forbidden\", \"message\": \"权限不足\"}";
                response.getWriter().write(json);
            })
        );

    return http.build(); 
}

2. 确保JWTTokenValidatorFilter逻辑正确

检查你的JWTTokenValidatorFilter实现:

  • 必须正确提取Authorization请求头中的Bearer <token>格式内容
  • 验证Token的签名、过期时间、Claims合法性
  • 验证失败时抛出AuthenticationException,触发上述配置的401响应

3. 验证Axios请求的Token有效性

  • 在Axios请求拦截器中打印config.headers.Authorization,确认请求头正确携带Bearer <token>
  • 确认localStorage中的Token未过期、格式正确

4. 前端处理异常(可选)

如果仍出现302,可在Axios响应拦截器中手动跳转前端登录页:

api.interceptors.response.use(
  response => response,
  error => {
    if (error.response?.status === 302) {
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:26:16