application.properties:

jwt.secret=密钥串
jwt.access-token-expiration=1800000访问 //token过期时间 单位: 秒
jwt.refresh-token-expiration=604800000 //刷新token过期时间 单位:秒

JwtUtil.java:


@Component
public class JwtUtil {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.access-token-expiration}")
    private long accessExpiration;

    @Value("${jwt.refresh-token-expiration}")
    private long refreshExpiration;

    // 生成 Access Token
    public String generateAccessToken(String username) {
        return buildToken(username, accessExpiration);
    }

    // 生成 Refresh Token
    public String generateRefreshToken(String username) {
        return buildToken(username, refreshExpiration);
    }

    // 从 Token 取用户名
    public String getUsernameFromToken(String token) {
        Claims claims = Jwts.parser()
                .verifyWith(getSignKey())
                .build()
                .parseSignedClaims(token)
                .getPayload();
        return claims.getSubject();
    }

    // 验证 Token 是否有效
    public boolean validateToken(String token) {
        try {
            Jwts.parser()
                    .verifyWith(getSignKey())
                    .build()
                    .parseSignedClaims(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    // 内部方法:构建 Token
    private String buildToken(String username, long expiration) {
        return Jwts.builder()
                .subject(username)
                .issuedAt(new Date())
                .expiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(getSignKey())
                .compact();
    }

    // 获取签名密钥
    private SecretKey getSignKey() {
        return Keys.hmacShaKeyFor(secret.getBytes());
    }
}

JwtInterceptor.java:


@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 1. 从 Header 取 Token
        String token = request.getHeader("Authorization");

        // 2. 没有 Token
        if (token == null || !token.startsWith("Bearer ")) {
            response.setStatus(401);
            return false;
        }

        // 3. 去掉 "Bearer " 前缀
        token = token.substring(7);

        // 4. 验证 Token
        if (!jwtUtil.validateToken(token)) {
            response.setStatus(401);
            return false;
        }

        // 5. 验证通过,放行
        return true;
    }

WebConfig.java:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private JwtInterceptor jwtInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/api/**")      // 拦截所有 /api/**
                .excludePathPatterns("/api/auth/login"); // 排除登录接口
    }
}

LoginController.java


@Controller
@RequestMapping("/api/auth")
public class LoginController {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest request) {
        //查找用户
        User user = userRepository.findByUsername(request.getUsername())
                .orElse(null);

        //验证密码
        if(user == null || user.getPassword().equals(request.getUsername())){
            return ResponseEntity.status(401).body("账号或密码错误");
        }

        //生成双 Token
        String accessToken = jwtUtil.generateAccessToken(user.getUsername());
        String refreshToken = jwtUtil.generateRefreshToken(user.getUsername());

        //返回
        return ResponseEntity.ok(Map.of(
                "accessToken", accessToken,
                "refreshToken", refreshToken
        ));
    }
}