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

Spring Security登录后用ResponseEntity重定向遇认证异常问题

解决登录重定向后认证失败的问题

问题原因

登录时通过SecurityContextHolder.getContext().setAuthentication(authentication)设置的认证信息仅在当前请求线程中有效,重定向会触发新的HTTP请求(对应新线程),原认证上下文不会自动传递。如果你的系统采用JWT认证模式,重定向的请求未携带JWT Token,后端无法识别已登录用户,因此抛出InsufficientAuthenticationException异常。

解决方案

场景1:基于Session的认证模式

如果系统使用Spring Security默认的Session认证,只需确保认证信息持久化到Session中,重定向时浏览器会自动携带Session Cookie完成认证:

  1. 在登录方法中注入HttpServletRequest,手动将SecurityContext存入Session:
@PostMapping("/login")
@Transactional
public ResponseEntity<?> login(@Valid @ModelAttribute("login") LoginDTO dto, Model model, HttpServletRequest request) {
    Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(dto.getUsername(), dto.getPassword()));
    SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
    securityContext.setAuthentication(authentication);
    
    // 将SecurityContext存入Session,保证重定向请求能获取到认证信息
    HttpSession session = request.getSession(true);
    session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, securityContext);
    
    // 省略RefreshToken生成等原有逻辑...
    
    HttpHeaders headers = new HttpHeaders();
    headers.add("Location", "/api/auth/index");
    return new ResponseEntity<>(headers, HttpStatus.FOUND);
}
  1. 确保Spring Security配置中Session创建策略为IF_REQUIRED(默认配置,未修改可跳过):
@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
            )
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/login").permitAll()
                .requestMatchers("/api/auth/index").authenticated()
                // 其他权限配置...
            );
        return http.build();
    }
}

场景2:基于JWT的认证模式

如果系统采用JWT认证,需要将生成的Access Token通过Cookie传递给浏览器,重定向时浏览器自动携带Cookie,后端从Cookie中读取Token完成认证:

  1. 登录方法中生成Token并设置到HttpOnly Cookie:
@PostMapping("/login")
@Transactional
public ResponseEntity<?> login(@Valid @ModelAttribute("login") LoginDTO dto, Model model, HttpServletResponse response) {
    Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(dto.getUsername(), dto.getPassword()));
    SecurityContextHolder.getContext().setAuthentication(authentication);
    User user = (User) authentication.getPrincipal();

    // 省略RefreshToken生成等原有逻辑...
    String accessToken = jwtHelper.generateAccessToken(user);
    
    // 将Access Token存入HttpOnly Cookie,提升安全性
    Cookie accessTokenCookie = new Cookie("access_token", accessToken);
    accessTokenCookie.setHttpOnly(true); // 防止XSS攻击
    accessTokenCookie.setSecure(true); // 生产环境启用HTTPS时开启
    accessTokenCookie.setPath("/"); // 所有路径可访问该Cookie
    accessTokenCookie.setMaxAge(3600); // 与JWT Token有效期保持一致
    response.addCookie(accessTokenCookie);
    
    HttpHeaders headers = new HttpHeaders();
    headers.add("Location", "/api/auth/index");
    return new ResponseEntity<>(headers, HttpStatus.FOUND);
}
  1. 修改JWT过滤器,支持从Cookie中读取Token:
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private final JwtHelper jwtHelper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = extractToken(request);
        if (token != null && jwtHelper.validateToken(token)) {
            Authentication authentication = jwtHelper.getAuthentication(token);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        filterChain.doFilter(request, response);
    }

    private String extractToken(HttpServletRequest request) {
        // 优先从Authorization Header读取Token
        String header = request.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            return header.substring(7);
        }
        // 从Cookie读取Token
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("access_token".equals(cookie.getName())) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }
}
  1. 确保Spring Security配置中,JWT过滤器被正确添加到过滤链,且/api/auth/index配置为允许已认证用户访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 07:55:21