Spring Security JWT登录接口无法向Postman返回Token问题
Spring Security JWT登录接口无法返回Token的问题修复
直接原因
你的loginUser方法中,虽然成功生成了JWT Token并创建了AuthenticationResponse对象,但最终返回的是固定字符串"Hiii"或"AHHHHHH",完全没有把包含Token的响应对象返回给前端,这就是Postman看不到Token的核心问题。
修正后的登录Controller方法
@RestController @RequestMapping("/auth") @CrossOrigin public class AuthController { @Autowired PasswordEncoder passwordEncoder; @Autowired AuthenticationManager authenticationManager; @Autowired BookingUserService bookingUserService; @Autowired RoleService roleService; @Autowired JWTUtil jwtUtil; @PostMapping(path = "/register") public ResponseEntity<?> registerUser(@Valid @RequestBody BookingUser registerBookingUser) { if (bookingUserService.existsByEmail(registerBookingUser.getEmail())) { return ResponseEntity.ok("邮箱已存在"); } BookingUser bookingUser = new BookingUser(registerBookingUser.getName(), registerBookingUser.getLastName(), registerBookingUser.getEmail(), passwordEncoder.encode(registerBookingUser.getPassword()), registerBookingUser.getCity(), registerBookingUser.getRole()); Role role = roleService.findByName(String.valueOf(RoleName.client)).get(); if(registerBookingUser.getRole().equals("admin")) role = roleService.findByName(String.valueOf(RoleName.admin)).get(); bookingUser.setRole(role); bookingUserService.createUser(bookingUser); return ResponseEntity.status(HttpStatus.CREATED).body("用户创建成功"); } @Deprecated @PostMapping(path = "/login") public ResponseEntity<?> loginUser(@RequestBody AuthenticationRequest request) { try { Authentication authentication = authenticationManager.authenticate (new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword())); SecurityContextHolder.getContext().setAuthentication(authentication); String jwt = jwtUtil.generateToken(authentication); // 创建包含Token的响应对象 AuthenticationResponse response = new AuthenticationResponse(jwt); System.out.println("生成的JWT: " + jwt); // 返回响应对象,而不是固定字符串 return new ResponseEntity<>(response, HttpStatus.OK); } catch (BadCredentialsException e) { return new ResponseEntity<>("用户名或密码错误", HttpStatus.FORBIDDEN); } } }
其他需要检查的细节
JWTUtil中的类型转换问题:
generateToken方法中直接把authentication.getPrincipal()强转为BookingUser,需要确保BookingUser类实现了UserDetails接口,否则会抛出类型转换异常。如果没有实现,应该先转为UserDetails,再通过邮箱查询对应的BookingUser对象。修正示例:
@Deprecated public String generateToken(Authentication authentication) { UserDetails userDetails = (UserDetails) authentication.getPrincipal(); // 通过邮箱查询BookingUser BookingUser user = bookingUserService.findByEmail(userDetails.getUsername()).get(); Map<String, Object> claims = new HashMap<>(); claims.put("lastname", user.getLastName()); claims.put("name", user.getName()); return Jwts.builder() .setSubject(user.getUsername()) .addClaims(claims) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) .signWith(SignatureAlgorithm.HS256, KEY).compact(); }AuthenticationResponse类优化:
为了确保Spring能正常序列化该对象,建议添加无参构造函数(配合Lombok的@NoArgsConstructor):@Setter @Getter @NoArgsConstructor // 添加无参构造 public class AuthenticationResponse { private String jwt; public AuthenticationResponse(String jwt) { this.jwt = jwt; } }JwtEntryPoint类完善:
当前commence方法为空,建议添加未授权响应逻辑,避免前端收到空响应:@Component public class JwtEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("{\"message\":\"未授权,请登录后访问\"}"); } }
其他类的中文注释版
JWT工具类(JWTUtil)
@Component public class JWTUtil { // JWT签名密钥(建议放到配置文件中,不要硬编码) private static final String KEY = "mG9\\n2,^obBu[8n.~MpVzbB5tHnuYF<KRE/LnQrQ<q@]wQP46vo^x{3vEN?3uN/E"; @Deprecated // 根据认证信息生成JWT Token public String generateToken(Authentication authentication) { BookingUser user = (BookingUser) authentication.getPrincipal(); Map<String, Object> claims = new HashMap<>(); claims.put("lastname", user.getLastName()); claims.put("name", user.getName()); return Jwts.builder() .setSubject(user.getUsername()) // 设置主题为用户名(邮箱) .addClaims(claims) // 添加自定义声明 .setIssuedAt(new Date()) // 设置签发时间 .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 设置过期时间(10小时) .signWith(SignatureAlgorithm.HS256, KEY) // 使用HS256算法签名 .compact(); } // 验证Token是否有效 public Boolean validateToken(String token, UserDetails userDetails) { return userDetails.getUsername().equals(extractUsername(token)) && !isTokenExpired(token); } // 从Token中提取用户名 public String extractUsername(String token) { return getClaims(token).getSubject(); } // 判断Token是否过期 public Boolean isTokenExpired(String token) { return getClaims(token).getExpiration().before(new Date()); } @Deprecated // 解析Token获取声明 private Claims getClaims(String token) { return Jwts.parser().setSigningKey(KEY).parseClaimsJws(token).getBody(); } }
登录请求体(AuthenticationRequest)
@Setter @Getter public class AuthenticationRequest { // 登录邮箱 private String email; // 登录密码 private String password; }
登录响应体(AuthenticationResponse)
@Setter @Getter @NoArgsConstructor public class AuthenticationResponse { // 返回的JWT Token private String jwt; public AuthenticationResponse(String jwt) { this.jwt = jwt; } }
内容的提问来源于stack exchange,提问作者EFF
相关产品推荐
相关产品推荐

