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

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);
        }
    }
}

其他需要检查的细节

  1. 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();
    }
    
  2. AuthenticationResponse类优化:
    为了确保Spring能正常序列化该对象,建议添加无参构造函数(配合Lombok的@NoArgsConstructor):

    @Setter
    @Getter
    @NoArgsConstructor // 添加无参构造
    public class AuthenticationResponse {
        private String jwt;
    
        public AuthenticationResponse(String jwt) {
            this.jwt = jwt;
        }
    }
    
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 21:25:20