本文最后更新于22 天前,其中的信息可能已经过时,如有错误请发送邮件到qiqin-chang@qq.com
依赖:
<!--JWT 令牌加密-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.3.0</version>
</dependency>
工具包:
旧:
生成Token 获取用户信息:
package com.chang.utils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.chang.entity.Account;
import com.chang.service.impl.AdminServiceImpl;
import com.chang.service.impl.EmployeeServiceImpl;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Date;
@Component
public class TokenUtils {
@Autowired
AdminServiceImpl adminService;
@Autowired
EmployeeServiceImpl employeeService;
static AdminServiceImpl staticAdminService;
static EmployeeServiceImpl staticEmployeeService;
//springboot工程启动后会加载这段代码
@PostConstruct
public void init(){
staticAdminService = adminService;
staticEmployeeService = employeeService;
}
/**
* 生成token
*/
public static String createToken(String data,String sign) {
return JWT.create().withAudience(data) //将userId-role 保存到token里面,作为载荷
.withExpiresAt(DateUtil.offsetDay(new Date(),1)) //1天后token过期
.sign(Algorithm.HMAC256(sign)); //秘钥签名 以password 作为token的秘钥,HMAC256算法加密
}
/**
* 获取当前登录用户信息
*/
public static Account getCurrentUser() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("token");
if (StrUtil.isBlank(token)){
token = request.getParameter("Token");
}
if (StrUtil.isBlank(token)){
return null;
}
//拿到token的载荷数据
String audience = JWT.decode(token).getAudience().get(0);
String[] split = audience.split("-");
String userId = split[0];
String role = split[1];
//根据token解析出来的userId去对应的表查询用户信息
if ("ADMIN".equals(role)){
return staticAdminService.selectById(Integer.valueOf(userId));
} else if ("EMP".equals(role)) {
return staticEmployeeService.selectById(Integer.valueOf(userId));
}
return null;
}
}
Service层login方法中:
生成token并返回给前端:
String token = TokenUtils.createToken(dbAdmin.getId() + "-" + "ADMIN", dbAdmin.getPassword());
dbAdmin.setToken(token);
获取当前用户信息:
Account currentUser = TokenUtils.getCurrentUser();
新:
package com.chang.utils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.chang.entity.Account;
import com.chang.service.impl.AdminServiceImpl;
import com.chang.service.impl.EmployeeServiceImpl;
import com.chang.service.impl.UserServiceImpl;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Date;
@Component
public class JWTUtils {
private static final String sign = "chang_2025";
@Autowired
AdminServiceImpl adminService;
@Autowired
EmployeeServiceImpl employeeService;
@Autowired
UserServiceImpl userService;
static AdminServiceImpl staticAdminService;
static EmployeeServiceImpl staticEmployeeService;
static UserServiceImpl staticUserService;
//springboot工程启动后会加载这段代码
@PostConstruct
public void init(){
staticAdminService = adminService;
staticEmployeeService = employeeService;
staticUserService = userService;
}
/**
* 生成 Token
*/
public static String createToken(Integer id, String role) {
return JWT.create()
.withClaim("id", id)
.withClaim("role", role) // 角色
.withExpiresAt(DateUtil.offsetDay(new Date(), 1)) // 1天后过期
.sign(Algorithm.HMAC256(sign));
}
/**
* 获取用户信息
* @return
*/
public static Account getCurrentUser() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("Token");
if (StrUtil.isBlank(token)) {
token = request.getParameter("Token");
}
if (StrUtil.isBlank(token)) {
return null; //只能进行静默处理
}
try {
// 1. 验签
DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC256(sign)).build().verify(token);
// 2. 解析 payload
Integer userId = decodedJWT.getClaim("id").asInt();
String role = decodedJWT.getClaim("role").asString();
// 根据角色查对应表
if ("ADMIN".equals(role)) {
return staticAdminService.selectById(userId); // 假设 username 是主键
} else if ("EMP".equals(role)) {
return staticEmployeeService.selectById(userId);
} else if ("USER".equals(role)) {
return staticUserService.selectById(userId);
}
} catch (Exception e) {
return null;
}
return null;
}
}
拦截器:
注册拦截器:
package com.chang.config;
import com.chang.interceptor.JWTInterceptor;
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.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor()).addPathPatterns("/**").excludePathPatterns("/login","/register");
}
@Bean
public JWTInterceptor jwtInterceptor() {
return new JWTInterceptor();
}
}
实现拦截器:
旧:
package com.chang.interceptor;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.chang.entity.Account;
import com.chang.exception.CustomException;
import com.chang.service.AdminService;
import com.chang.service.EmployeeService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class JWTInterceptor implements HandlerInterceptor {
@Autowired
AdminService adminService;
@Autowired
EmployeeService employeeService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.从请求头中获取token
String token = request.getHeader("Token");
if (StrUtil.isEmpty(token)){
//如果没拿到,从参数里再拿一次
token = request.getParameter("Token");
}
//2.认证token
if (StrUtil.isBlank(token)){
throw new CustomException("401","您无权限操作");
}
Account account = null;
try{
//拿到token的载荷数据
String audience = JWT.decode(token).getAudience().get(0);
String[] split = audience.split("-");
String userId = split[0];
String role = split[1];
//根据token解析出来的userId去对应的表查询用户信息
if ("ADMIN".equals(role)){
account = adminService.selectById(Integer.valueOf(userId));
} else if ("EMP".equals(role)) {
account = employeeService.selectById(Integer.valueOf(userId));
}
}catch (Exception e){
throw new CustomException("401","您无权限操作");
}
if (account == null){
throw new CustomException("401","您无权限操作");
}
//验证签名
try {
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(account.getPassword())).build();
jwtVerifier.verify(token);
}catch (Exception e){
throw new CustomException("401","您无权限操作");
}
return true;
}
}
新:
package com.chang.interceptor;
import cn.hutool.core.util.StrUtil;
import com.chang.entity.Account;
import com.chang.exception.CustomException;
import com.chang.utils.TokenUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class JWTInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.从请求头中获取token
String token = request.getHeader("Token");
if (StrUtil.isEmpty(token)){
//如果没拿到,从参数里再拿一次
token = request.getParameter("Token");
}
//2.认证token
if (StrUtil.isBlank(token)){
throw new CustomException("401", "未检测到登录凭证,请先登录");
}
Account account = TokenUtils.getCurrentUser();
if (account == null) {
throw new CustomException("401", "Token无效或已过期,请重新登录");
}
return true;
}
}
前端:
设置拦截器:
utils包:
request.js:
添加请求头 处理错误信息:
import axios from 'axios';
import {ElMessage} from 'element-plus';
import router from "@/router/index.js";
const request = axios.create({
baseURL:'http://localhost:9090',
timeout:30000, //后台接口超时时间
})
//request 拦截器
//可以自动请求发送前对请求做的一些处理
request.interceptors.request.use(
config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
let user = JSON.parse(localStorage.getItem('chang-user')||'{}');
config.headers['token'] = user.token
return config;
},
error => {
return Promise.reject(error);
}
)
//response 拦截器
//可以在接口响应后统一处理结果
request.interceptors.response.use(
response => {
let res = response.data;
//兼容服务端返回的字符串数据
if (typeof res === 'string') {
res = res ? JSON.parse(res) : res;
}
if (res.code === '401') {
ElMessage.error(res.msg);
router.push('/login');
}else{
return res;
}
return res;
},
error => {
if (error.response.status === 404) {
ElMessage.error('未找到请求接口')
}else if (error.response.status === 500) {
ElMessage.error('系统异常,请查看后端控制台报错')
}else {
console.error(error.message);
}
return Promise.reject(error);
}
)
export default request;
拼接Token令牌:
eg:更改导出数据代码:
user:JSON.parse(localStorage.getItem('chang-user')||'{}'),
//导出数据
const exportData=()=>{
let url = `http://localhost:9090/employee/export`
+ `?Token=${data.user.token}`;
//导出数据 是通过流的形式下载 excel 打开流的连接,浏览器会自动帮我们下载文件
window.open(url);
}