SpringBoot整合JWT
什么是JWT:https://www.jianshu.com/p/576dbf44b2ae
一、导入依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.19.2</version>
</dependency>
二、生成JWT
@Component
@Slf4j
public class TokenUtils {
private static UserService staticUserService;
@Autowired
private UserService userService;
@PostConstruct
public void setStaticUserService() {
staticUserService = userService;
}
// 重点 生成token
public static String genToken(String userId, String sign) {
return JWT.create()
.withAudience(userId) // 载荷
.withExpiresAt(DateUtil.offsetMinute(new Date(), 10)) // 10分钟后token过期
.sign(Algorithm.HMAC256(sign)); // 以password作为token密钥
}
// 根据载荷中的id获取当前用户信息
public static User getCurrentUser() {
User user = null;
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("token");
if (StrUtil.isNotBlank(token)) {
String userId = JWT.decode(token).getAudience().get(0);
user = staticUserService.getById((Integer.valueOf(userId)));
}
} catch (JWTDecodeException | NumberFormatException e) {
log.error(e.toString());
}
return user;
}
}
在登录的接口中调用该方法,将生成的token返回给前端
@Override
public UserDTO login(UserDTO userDTO) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("ds_user_name", userDTO.getUsername())
.eq("ds_user_password", userDTO.getPassword());
User user = null;
try {
user = getOne(wrapper);
if (user != null) {
userDTO.setUsername(user.getDsUserName());
String token = TokenUtils.genToken(user.getDsUserId().toString(), user.getDsUserPassword());
userDTO.setToken(token );
userDTO.setPassword(null);
} else {
userDTO = null;
}
} catch (Exception e) {
log.error(e.toString());
userDTO = null;
}
return userDTO;
}
三、前端接收token
将传回的token存放在浏览器中:
this.api.userApi.signIn(this.user)
.then(res => {
if (res.code === '200') {
localStorage.setItem('user', JSON.stringify(res.data))
this.$router.push("/home")
this.$message.success('登录成功!')
}
})
并在request.js中加上这一段,让每个请求都带上token
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
let user = JSON.parse(localStorage.getItem('user'))
if (user) config.headers['token'] = user.token; // 设置请求头
return config
}, error => {
return Promise.reject(error)
});
四、后端验证token
因为每个请求头中都包含当前用户的token,所以我们可以做一个拦截器,让非法请求无法获得数据:
实现HandlerInterceptor接口
@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
// 检查方法是否需要过滤
if (!(handler instanceof HandlerMethod)) return true;
// 初步验证token
if (StrUtil.isBlank(token)) {
log.error("不要乱搞");
return false;
}
String userId;
try {
userId = JWT.decode(token).getAudience().get(0);
// 查看是否有该用户
User user = userService.getById(Integer.valueOf(userId));
if (user == null) {
log.error("不要乱搞");
return false;
} else {
// 验证签证
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getDsUserPassword())).build();
jwtVerifier.verify(token);
}
} catch (JWTDecodeException e) {
e.printStackTrace();
log.error(e.toString());
}
return true;
}
}
五、配置拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/**")
// 不能直接 **/login必须加 /
.excludePathPatterns("/**/login", "swagger/**", "/swagger-ui.html", "swagger-ui.html", "/webjars/**", "/swagger-ui.html/*", "/swagger-resources", "/swagger-resources/**");
}
}