SpringBoot 进阶
JWT
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用环境间安全地传递信息。信息以 JSON 对象的形式进行编码,经过签名保证安全性,通常用于身份验证和信息交换。

一个 JWT 实际上是一个字符串,它由三部分组成,每部分之间用点(.
)分隔,然后经过 Base64 处理:
- Header(头部)
- Payload(负载)
- Signature(签名)
1
| eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
|
头部通常包括两部分:令牌的类型(即 JWT)和所使用的签名算法(例如 HMAC SHA256 或 RSA)。
1 2 3 4
| { "alg": "HS256", "typ": "JWT" }
|
2. Payload
负载部分包含所要传递的信息,这些信息称为 claims(声明)。声明是关于实体(通常是用户)和其他数据的语句。有三种类型的声明:注册声明、公共声明和私有声明。
1 2 3 4 5 6
| { "sub": "1234567890", "name": "John Doe", "admin": true, "iat": 1516239022 }
|
3. Signature
要创建签名部分,必须使用头部指定的算法(例如 HMAC SHA256)对 header 和 payload 进行编码,并使用一个密钥。签名用于确认消息在传输过程中未被篡改、并验证发送方的身份。
拦截器

定义拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import org.springframework.web.servlet.HandlerInterceptor;
@Component public class MyInterceptor extends HandlerInterceptor {
@Override public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) { }
@Override public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, @Nullable Exception ex) { } }
|
注册拦截器
实现 WebMvcConfigurer 类,通过重写 addInterceptors 方法添加拦截器
1 2 3 4 5 6 7 8 9 10 11
| @Configuration public class InterceptorConfig implements WebMvcConfigurer {
@Resource private MyInterceptor interceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(interceptor).excludePathPatterns("/login"); } }
|
在拦截器中处理 JWT
一般来说,JWT 参数添加在请求头中

1 2 3 4 5 6 7 8 9 10 11
| @Override public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) { String header = request.getHeader("Authorization"); if (header == null || !header.startsWith("Bearer ")) { throw new IllegalStateException("Please login first"); } String token = header.substring(7); return true; }
|
JWT 工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;
import java.time.Duration; import java.time.Instant; import java.util.Map;
@Component public class JwtUtil {
private final Algorithm algorithm; private final JWTVerifier verifier; private final Duration defaultExpireTime;
public JwtUtil(@Value("${app.security.jwt.secret}") String secret, @Value("${app.security.jwt.expiresIn}") Long expiresInMinutes) { this.algorithm = Algorithm.HMAC512(secret); this.verifier = JWT.require(algorithm).build(); this.defaultExpireTime = Duration.ofMinutes(expiresInMinutes); }
public DecodedJWT verify(String token) { try { return verifier.verify(token); } catch (JWTVerificationException e) { throw new IllegalArgumentException("Invalid JWT token"); } }
public String generateAccessToken(String id) { return generateAccessToken(id, defaultExpireTime); }
public String generateAccessToken(String id, Duration expireTime) { Instant now = Instant.now(); return JWT.create() .withSubject(id) .withIssuedAt(now) .withExpiresAt(now.plus(expireTime)) .sign(algorithm); }
public String generateAccessTokenWithClaims(String id, Map<String, String> claims) { Instant now = Instant.now(); var jwtBuilder = JWT.create() .withSubject(id) .withIssuedAt(now) .withExpiresAt(now.plus(defaultExpireTime)); claims.forEach(jwtBuilder::withClaim); return jwtBuilder.sign(algorithm); }
public boolean isTokenExpired(DecodedJWT decodedJWT) { Instant expiresAt = decodedJWT.getExpiresAt().toInstant(); return Instant.now().isAfter(expiresAt); } }
|
MyBatis
MyBatis 是一个持久层框架。它将 SQL 语句从 Java 代码中分离出来,并通过 XML 配置文件或注解的方式进行管理。
基本概念
- <mapper>:定义了命名空间以及 SQL 语句和映射定义。
- <select>、<insert>、<update>、<delete>:定义具体的 SQL 语句。通过
id
属性标识,对应 mapper 接口的方法名。
- <resultMap>:定义了如何从数据库结果集中映射数据为 Java 对象。
- #{id}:表示参数占位符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="fun.sast.sasttodo.mapper.TaskMapper"> <resultMap id="taskResultMap" type="fun.sast.sasttodo.entity.Task"> <id property="id" column="id" /> <result property="title" column="title" /> ... </resultMap>
<select id="selectTask" resultMap="taskResultMap"> SELECT id, title FROM task WHERE id = #{id} </select>
<insert id="insertTask"> INSERT INTO task (id, title) VALUES (#{id}, #{title}) </insert>
<update id="updateTask"> UPDATE task SET title = #{title} WHERE id = #{id} </update>
<delete id="deleteTask"> DELETE FROM task WHERE id = #{id} </delete> </mapper>
|