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

未登录无法访问/api/users/**,登录后仍提示未授权的问题

问题分析

核心问题出在JWT Cookie未正确写入响应,以及无状态会话配置与formLogin的冲突:

  1. 你设置了SessionCreationPolicy.STATELESS,Spring Security不会维护会话,所有请求必须通过JWT Cookie携带认证信息才能通过/api/users/**的权限校验。
  2. 登录接口中,ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, jwtCookie.toString())这行代码只是创建了一个未使用的ResponseEntity对象,真正返回的ResponseEntity的headers里只添加了Location,没有把JWT Cookie写入响应头,导致浏览器没有存储Cookie,重定向到首页时请求不带认证信息,触发401。
  3. 同时你混用了formLogin和自定义JWT认证流程,formLogin默认依赖会话,和无状态模式不兼容,会干扰认证逻辑。
解决方案

1. 修复登录接口的Cookie写入逻辑

修改登录方法,确保JWT Cookie被正确添加到响应头:

@PostMapping("/login")
@Transactional
public ResponseEntity<?> login(@Valid @ModelAttribute("login") LoginRequest loginRequest, Model model) {
    Authentication authentication = authenticationManager
            .authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
    SecurityContextHolder.getContext().setAuthentication(authentication);
    UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();

    ResponseCookie jwtCookie = jwtHelper.generateJwtCookie(user);

    model.addAttribute("login", loginRequest);

    HttpHeaders headers = new HttpHeaders();
    // 正确添加JWT Cookie到响应头
    headers.add(HttpHeaders.SET_COOKIE, jwtCookie.toString());
    headers.add("Location", "/api/users/tripAdvisorHomePage");
    return new ResponseEntity<>(headers, HttpStatus.FOUND);
}

2. 调整Security配置,移除冲突的formLogin配置

因为你使用JWT无状态认证,formLogin的配置(基于会话)会和当前模式冲突,建议移除formLogin相关配置,完全基于JWT处理认证:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable()
            .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests()
            .antMatchers("/api/auth/**").permitAll()
            .antMatchers("/api/users/**").authenticated()
            .antMatchers(h2ConsolePath + "/**").permitAll().and()
            .logout()
            .logoutUrl("/api/auth/logout")
            .logoutSuccessUrl("/api/auth/loginAndRegisterForm")
            .permitAll();
    http.headers().frameOptions().sameOrigin();
    http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}

如果需要保留登录页面的跳转逻辑,可以在/api/auth/loginAndRegisterForm接口中返回登录视图,由前端发起POST请求到/api/auth/login完成认证。

3. 验证JWT过滤器逻辑

确保你的authenticationJwtTokenFilter()能正确从Cookie中提取JWT,并完成认证:

  • 过滤器需要从请求的Cookie中获取JWT令牌
  • 解析令牌并加载用户信息,将认证信息存入SecurityContextHolder
额外说明
  • 无状态模式下,Spring Security不会自动维护登录状态,所有请求必须携带有效的JWT(通过Cookie或请求头)
  • 重定向请求会自动携带浏览器存储的Cookie,只要登录时正确写入Cookie,后续请求就能通过JWT过滤器完成认证

内容的提问来源于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 12:50:16