添加JWT依赖

1
2
3
4
5
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>

添加工具类,包含

  • 生成Token方法
  • 从token中获取userId
  • 从token中获取userName
  • 查看Token是否过期
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
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.szx.exam.util;

import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;
import java.util.Date;

/**
* @author songzx
* @create 2023-06-25 13:55
*/
public class JwtHelper {
// 随机字符串混淆Token
private static final String tokenSignKey = "uNvs^pML-E";

/**
* 生成Token,并保存userID和userName信息
* @param userId
* @param userName
* @return
*/
public static String createToken(Long userId, String userName) {
long tokenExpiration = 1000L * 60 * 60 * 24 * 30; // 过期时间,设置30天
String token = Jwts.builder()
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
.claim("userName", userName)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}

/**
* 从token中获取userID
* @param token
* @return
*/
public static Long getUserId(String token) {
if (StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer) claims.get("userId");
return userId.longValue();
}

/**
* 从token中获取用户姓名
* @param token
* @return
*/
public static String getUserName(String token) {
if (StringUtils.isEmpty(token)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String) claims.get("userName");
}

/**
* 查看Token是否过期
* @param token
* @return false 未过期,true 已过期
*/
public static Boolean tokenExpired(String token) {
try {
Claims claims = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
Date expiration = claims.getExpiration();
Date currentDate = new Date();
return expiration.before(currentDate);
} catch (ExpiredJwtException ex) {
return true;
} catch (Exception ex) {
return true;
}
}
}

添加 handle

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
package com.szx.exam.handle;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.szx.exam.exception.SsyxException;
import com.szx.exam.util.JwtHelper;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @author songzx
* @create 2022-10-12 9:48
*/
public class TokenHandle implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(!(handler instanceof HandlerMethod)){
return true;
}
// 从请求头中获取token
String token = request.getHeader("X-Token");
// 校验token
if(StringUtils.isEmpty(token) || JwtHelper.tokenExpired(token)){
throw new SsyxException("登录过期,请重新登录",401);
}
return true;
}
}

添加 TokenConfig,设置需要过滤的接口信息,不在过滤中的接口都将配拦截校验是否存在token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.szx.exam.config;

import com.szx.exam.handle.TokenHandle;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
* @author songzx
* @create 2022-10-12 9:51
*/
@Configuration
public class TokenConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TokenHandle())
.addPathPatterns("/**")
.excludePathPatterns("/","/stu/login","/webjars/**","/fonts/**","/images/**","/swagger-ui.html");
}
}

测试

有如下接口:

http://localhost:9000/exam/saveExam

image-20230625153900273

在不加Token的情况下,或者Token已经过期的情况下, 发起请求,返回401

image-20230625154226048

现在生成一个Token,

image-20230625154504196

将得到的Token加在请求头中,再次发起请求

image-20230625154435476

可以看到本次请求正常返回200