一次学会JWT:Java 登录、验证与权限控制全流程
目录
3.2 再封装一个 JwtUtil 工具类,用于生成和验证 Token。
3.4 创建一个拦截器(JwtInterceptor.java)
1. JWT 基础概念
1.1 什么是 JWT?
JWT(JSON Web Token)是一种基于 JSON 的轻量级认证方式,用于在各方之间安全地传递信息。它常用于 前后端分离项目的登录认证,替代传统的 Session 机制。
特点:数据量小,传输快(轻量)、本身携带用户信息,不依赖服务端存储(自包含)、签名保证数据完整性与可信度(签名防篡改)。
1.2 为什么要用 JWT?
传统的登录认证方式使用 Session 保存用户信息,但在 前后端分离 项目中:
-
Session 需要服务端存储,会增加服务器压力
-
多台服务器要共享 Session,需要引入 Redis
-
移动端、小程序调用不方便
而 JWT(JSON Web Token):
-
无需服务端保存状态,无状态认证
-
Token 自包含用户信息
-
轻量、安全、跨平台
1.3 JWT 的结构
JWT 一般由三部分组成,用 . 分隔:
Header.Payload.Signature
Header(头部)
声明签名算法和类型,例如:
{
"alg": "HS256",
"typ": "JWT"
}
alg: 使用的签名算法,如 HS256(HMAC SHA-256)、RS256(RSA SHA-256)等。
typ: 类型,固定为 JWT。
Payload(载荷)
存放实际信息(Claims),分为:
-
Registered claims(注册字段):如
iss(签发者)、exp(过期时间)等 -
Public claims(公共字段):自定义但公开的字段
-
Private claims(私有字段):自定义且内部使用
常用的字段(大家约定俗称的字段,表示一些通用的信息)
| 字段 | 含义 | 示例 |
|---|---|---|
sub |
用户唯一标识(Subject) | "sub": "user_10086" |
exp |
过期时间(Expiration) | "exp": 1723545600(时间戳) |
iat |
签发时间(Issued At) | "iat": 1723459200 |
iss |
签发者(Issuer) | "iss": "myapp.com" |
⏰ 提醒:exp 最常用,用来控制 token 的有效期。
{
"sub": "user123",
"exp": 1723545600,
"iss": "Yq",
"iat": 1723459200,
}
自定义信息(这部分是你自己决定要告诉别人的信息)
{
"name": "Yang",
"role": "管理员",
"email": "YangQ@example.com"
}
⚠️ 注意:Payload 是 Base64 编码的,不是加密的! 所以不要在其中存放敏感信息(如密码)。
Signature(签名)
用密钥和前两部分生成的签名,防止数据被篡改。如(使用HMAC SHA256):
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
2. JWT 的工作流程
-
用户登录 → 服务器验证身份
-
服务器生成 JWT 并返回给客户端
-
客户端每次请求都带上 JWT(通常放在 HTTP Header 中
Authorization: Bearer <token>) -
服务器验证 JWT 的合法性 → 允许访问资源
优点:无状态、轻量、跨域支持
缺点:无法轻易撤销(需维护黑名单)
3. Java中操作JWT
Java 生态中最流行的 JWT 库是 jjwt,由 Apache 提供,简单易用。
3.1 我们先创建 Spring Boot 项目并引入依赖
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
3.2 再封装一个 JwtUtil 工具类,用于生成和验证 Token。
package com.yg.jwt.util;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
public class JwtUtil {
// 建议从配置文件读取
private static final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
private static final long EXPIRATION = 60 * 1000; // 1分钟
// 生成 Token
public static String generateToken(String username, String role) {
return Jwts.builder()
.setSubject(username)
.claim("role", role)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(key)
.compact();
}
// 解析 Token
public static Claims parseToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
}
}
3.3 实现登录接口
package com.yg.jwt.controller;
import org.springframework.web.bind.annotation.*;
import com.yg.jwt.util.JwtUtil;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/login")
public Map<String, Object> login(@RequestParam String username, @RequestParam String password) {
Map<String, Object> result = new HashMap<>();
// 模拟账号密码验证
if ("admin".equals(username) && "123456".equals(password)) {
String token = JwtUtil.generateToken(username, "admin");
result.put("code", 200);
result.put("message", "登录成功");
result.put("token", token);
} else {
result.put("code", 401);
result.put("message", "用户名或密码错误");
}
return result;
}
}
3.4 创建一个拦截器(JwtInterceptor.java)
拦截请求,用来验证 Token 是否有效。
package com.yg.jwt.interceptor;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import com.yg.jwt.util.JwtUtil;
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
try {
Claims claims = JwtUtil.parseToken(token);
request.setAttribute("username", claims.getSubject());
request.setAttribute("role", claims.get("role"));
return true;
} catch (ExpiredJwtException e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Token 已过期");
return false;
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("无效 Token");
return false;
}
}
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("缺少 Token");
return false;
}
}
3.5 配置拦截器
package com.yg.jwt.config;
import com.yg.jwt.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/auth/login"); // 登录接口放行
}
}
💡 小插曲:为什么要配置拦截器?
因为MVC 框架需要知道“有哪些拦截器要工作”(注册机制)、统一处理(避免在每个 Controller 里重复写验证逻辑)、全局控制(可以精确控制拦截哪些路径、放行哪些路径)、流程集成(拦截器是 MVC 生命周期的一部分,必须接入流程)
3.6 编写受保护接口
package com.yg.jwt.controller;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/info")
public String getUserInfo(@RequestAttribute("username") String username,
@RequestAttribute("role") String role) {
return "当前用户:" + username + ",角色:" + role;
}
}
3.7 项目结构图
jwt
│── pom.xml # Maven 依赖
│── src
│ ├── main
│ │ ├── java
│ │ │ └── com.yq.jwt
│ │ │ ├── config
│ │ │ │ └── WebConfig.java # 配置拦截器
│ │ │ ├── controller
│ │ │ │ ├── AuthController.java # 登录接口
│ │ │ │ └── UserController.java # 受保护接口
│ │ │ ├── interceptor
│ │ │ │ └── JwtInterceptor.java # JWT 拦截器
│ │ │ └── util
│ │ │ └── JwtUtil.java # JWT 工具类
│ │ └── resources
│ │ └── application.yml # 配置文件
│ └── test
│ └── java # 测试代码
4. 测试流程
本篇章用的测试工具为Apifox,使用其他测试工具也是可以的(如:Postman)。
4.1 登录获取 Token
POST http://localhost:8080/auth/login
参数:
username=admin
password=123456
返回:

4.2 访问受保护接口
GET http://localhost:8080/user/info
Header:
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
把刚刚从后端返回回来的token放到Headers里面,接着访问后端请求数据

5. 总结
JWT 是一种轻量、跨域、无状态的认证方式,非常适合现代 Web 和微服务架构。通过 Java 的 jjwt 库,我们可以快速生成、解析和验证 JWT,实现安全的身份验证机制。
💬 如果你想要完整的 Spring Boot + JWT 登录认证项目源码,可以在评论区留言。
💬如果你觉得这篇文章有帮助,别忘了点赞、分享!👍
更多推荐
所有评论(0)