在前后端分离的项目中,JWT(JSON Web Token) 是一种非常流行的用户认证机制。相比传统的 Session,JWT 更加轻量、易扩展,特别适合前后端分离、移动端 API 场景。
今天我们基于 Spring Boot + JWT,完整实现一套 登录生成 Token + 认证拦截器校验 Token 的流程,并附完整示例代码,助你轻松上手。
📌 项目背景
-
技术栈:Spring Boot + MyBatis + JWT
-
功能目标:
- 用户登录,生成 Token
- 后续请求带 Token 自动鉴权
- 无需 Session,支持跨服务调用
🧩 一、登录接口:生成 JWT Token
typescript
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody Map<String, String> loginRequest) {
String username = loginRequest.get("username");
String password = loginRequest.get("password");
// 1. 数据库查用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
User user = userMapper.selectOne(queryWrapper);
if (user == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名不存在");
}
// 2. 验证密码
if (!passwordEncoder.matches(password, user.getPassword())) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("密码错误");
}
// 3. 登录成功,生成 JWT
String token = JwtUtils.generateToken(user); // 👈 自定义工具类
Map<String, String> response = new HashMap<>();
response.put("token", token);
response.put("message", "登录成功");
return ResponseEntity.ok(response);
}
- 登录成功后,前端拿到
token
,后续请求都通过请求头Authorization: Bearer <token>
携带。
🔑 二、JWT 工具类(JwtUtils)
typescript
public class JwtUtils {
private static final String SECRET_KEY = "your-secret-key";
private static final long EXPIRATION_TIME = 3600000; // 1 小时
// 生成 Token
public static String generateToken(User user) {
return Jwts.builder()
.setSubject(user.getUsername())
.claim("role", user.getRole()) // 可扩展更多字段
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
// 解析 Token
public static Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
}
🧱 三、JWT 认证过滤器:拦截每个请求校验 Token
java
public class JwtAuthenticationFilter implements Filter {
private static final String SECRET_KEY = "your-secret-key";
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String token = getTokenFromRequest(httpRequest);
System.out.println("JWT token: " + token); // ✅ 打印调试
if (StringUtils.hasText(token)) {
try {
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
String username = claims.getSubject();
String role = claims.get("role", String.class);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
username,
null,
Collections.emptyList() // 可以配置权限
);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (Exception e) {
System.out.println("JWT解析失败: " + e.getMessage());
}
}
chain.doFilter(request, response);
}
private String getTokenFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7); // 去掉 Bearer 前缀
}
return null;
}
}
🧠 拦截器作用:
- 自动从请求头解析 Token
- 校验签名、过期时间
- 如果合法,向 Spring Security 注入
Authentication
对象,代表当前用户已认证
⚙️ 四、注册过滤器(Spring Security 环境)
如果使用 Spring Security,可以将 JwtAuthenticationFilter
注册到过滤链中:
scss
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.build();
}
}
📋 五、前端如何携带 Token 请求
前端登录后,拿到后端返回的 token
,之后的所有请求都加上请求头:
php
axios.get('/api/user/info', {
headers: {
Authorization: 'Bearer ' + token
}
})
如果你用的是 Fetch:
php
fetch('/api/user/info', {
headers: {
'Authorization': 'Bearer ' + token
}
});
✅ 最终效果演示
- 调用
/login
,返回:
json
{
"token": "eyJhbGciOiJIUzI1NiIsInR...",
"message": "登录成功"
}
- 访问需要认证的接口,如
/user/info
,带上 token,返回成功数据。 - 如果 token 错误或过期,会被过滤器拦截,返回未认证提示。
✍️ 总结
步骤 | 内容 |
---|---|
1️⃣ | 登录成功生成 JWT |
2️⃣ | 前端保存 token 并携带请求 |
3️⃣ | 后端过滤器拦截校验 JWT |
4️⃣ | 注入认证信息,实现无状态登录 |
🎁 附加建议:
- 可以使用 Redis 存储 Token 黑名单,实现退出登录/踢人下线。
- 生产环境务必设置合适的 Token 过期时间、密钥强度。
- 登录成功返回 token 的同时,也可以返回用户信息。
📌 如果你觉得这篇文章对你有帮助,欢迎点赞 + 收藏 + 关注!我会持续更新更多 Java 项目实战和技术干货。