目录
一、什么是JWT:
二、Jwt的使用:
第一步:引入依赖:
第二步:配置拦截器:JwtInterceptor.java:
其中异常文件ServiceException配置如下:
全局异常文件GlobalException.java文件配置如下:
其中所需的Result配置如下:
第三步:配置拦截设置文件:InterceptorConfig.java:
第四步:配置Token工具类文件:TokenUtils.java:
request.js的axios封装文件为:
文件布局大致如下:
一、什么是JWT:
JWT是token的一种实现方式,全称是:JSON Wwb Token。简单来讲,Jwt是一种字符串,可以根据用户信息进行相关的编码操作生成带有用户信息的JWT token,我们可以根据这个来判断其信息是否正确或者是否被篡改。
二、Jwt的使用:
首先是后端:
第一步:引入依赖:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.3.0</version>
</dependency>
第二步:配置拦截器:JwtInterceptor.java:
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.example.cqcrhouduan.Utils.TokenUtils;
import com.example.cqcrhouduan.exception.ServiceException;
import com.example.cqcrhouduan.mapper.UserMapper;
import io.micrometer.common.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
private UserMapper userMapper;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if(request.getMethod().equals("OPTIONS"))
{
return true;
}
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
token = request.getParameter("token");
}
token = token;
// 执行认证
if (StringUtils.isEmpty(token)) {
throw new ServiceException(401, "无token,请重新登录");
}
// 获取 token 中的adminId
String userId;
User user;
try {
userId = JWT.decode(token).getAudience().get(0); //解码
// 根据token中的userid查询数据库
user = userMapper.getById(Integer.parseInt(userId));
user = user;
} catch (Exception e) {
String errMsg = "token验证失败,请重新登录";
log.error(errMsg + ", token=" + token, e);
throw new ServiceException(401, errMsg);
}
if (user == null) {
throw new ServiceException(401, "用户不存在,请重新登录");
}
try {
// 用户密码加签验证 token
JWTVerifier jwtVerifier =
JWT.require(Algorithm.HMAC256(user.getPassword())).build();
jwtVerifier.verify(token); // 验证token
} catch (JWTVerificationException e) {
throw new ServiceException(401, "token验证失败,请重新登录");
}
return true;
}
}
其中异常文件ServiceException配置如下:
import com.example.cqcrhouduan.pojo.Result;
import lombok.Data;
@Data
public class ServiceException extends RuntimeException {
private int code;
public ServiceException(String msg){
super(msg);
this.code = 500;
}
public ServiceException(int code, String msg){
super(msg);
this.code = code;
}
}
全局异常文件GlobalException.java文件配置如下:
import com.example.cqcrhouduan.pojo.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
//自定义异常
@ControllerAdvice
public class GlobalException {
@ExceptionHandler(ServiceException.class)
@ResponseBody
public Result serviceException(ServiceException e){
return Result.error(e.getCode(),e.getMessage());
}
}
其中所需的Result配置如下:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code;
private String msg;
private Object data;
public static Result success(Object data){
return new Result(200,"success",data);
}
public static Result success(){
return new Result(200,"success",null);
}
public static Result error(String msg){
return new Result(500,msg,null);
}
public static Result error(Integer Code ,String msg){
return new Result(Code,msg,null);
}
}
第三步:配置拦截设置文件:InterceptorConfig.java:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
// 加自定义拦截器JwtInterceptor,设置拦截规则
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login","/register");
super.addInterceptors(registry);
}
@Bean
public JwtInterceptor jwtInterceptor(){
return new JwtInterceptor();
}
}
第四步:配置Token工具类文件:TokenUtils.java:
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.cqcrhouduan.mapper.UserMapper;
import com.example.cqcrhouduan.pojo.User;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Component
@Slf4j
public class TokenUtils {
private static UserMapper staticAdminService;
@Resource
private UserMapper adminService;
@PostConstruct
public void setUserService() {
staticAdminService = adminService;
}
/**
* 生成token
*
* @return
*/
public static String genToken(int adminId, String sign) {
return JWT.create().withAudience(Integer.toString(adminId)) // 将 user id 保存到 token 里面,作为载荷
.withExpiresAt(DateUtil.offsetHours(new Date(), 2)) // 2小时后token过期
.sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥
}
/**
* 获取当前登录的用户信息
*
* @return user对象
* /admin?token=xxxx
*/
public static User getCurrentAdmin() {
String token = null;
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
token = request.getHeader("token");
if (StringUtils.isNotBlank(token)) {
token = request.getParameter("token");
}
if (StringUtils.isBlank(token)) {
log.error("获取当前登录的token失败, token: {}", token);
return null;
}
String userId = JWT.decode(token).getAudience().get(0);
return staticAdminService.getById(Integer.valueOf(userId));
} catch (Exception e) {
log.error("获取当前登录的管理员信息失败, token={}", token, e);
return null;
}
}
}
然后是前端axios配置:
request.js的axios封装文件为:
import axios from "axios";
import router from "../modules/router.js";
const request = axios.create({
baseURL:'http://localhost:8080/', //自己的请求地址
timeout:30000,
})
// Add a request interceptor
request.interceptors.request.use((config) => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
let user = JSON.parse(localStorage.getItem("userToken") || '{}')
// console.log(user.token) //查看token
config.headers['token'] = user.token
// config.headers.Authorization = localStorage.getItem("userToken")
console.log("ok")
// Do something before request is sent
return config;
}, error => {
console.log('request error' + error)
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
request.interceptors.response.use(response => {
let res = response.data;
if (typeof res === 'string'){
res = res ? JSON.parse(res) : res
}
// if(res.code === 401){ //自动跳转
// router.push('/')
// }
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return res;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
console.log('response error' + error)
return Promise.reject(error);
});
export default request