未登录无法访问/api/users/**,登录后仍提示未授权的问题
问题分析
核心问题出在JWT Cookie未正确写入响应,以及无状态会话配置与formLogin的冲突:
- 你设置了
SessionCreationPolicy.STATELESS,Spring Security不会维护会话,所有请求必须通过JWT Cookie携带认证信息才能通过/api/users/**的权限校验。 - 登录接口中,
ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, jwtCookie.toString())这行代码只是创建了一个未使用的ResponseEntity对象,真正返回的ResponseEntity的headers里只添加了Location,没有把JWT Cookie写入响应头,导致浏览器没有存储Cookie,重定向到首页时请求不带认证信息,触发401。 - 同时你混用了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
相关产品推荐
相关产品推荐

