做鉴权原因:
管理系统的数据是敏感的,隐私的,每个角色的权限是不同的,必须在数据的增删改查操作时候对访问的用户进行权限验证
JWT(Json Web Token)
用于在网络应用间安全的传递消息。它以紧凑且自包含的方式,通过JSON对象在各方之间传递经过验证的信息。JWT通常由三部分组成,用点号(.)分隔:header.payload.signature
集成JWT(在pom中引入依赖)
<!--java-JWT坐标 --><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version></dependency>
生成token
/*** 生成 JWT 令牌*/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算法加密}
在***Service中创建token返回前端
String token = TokenUtil.createToken(dbUser.getId()+"-"+"管理员",dbUser.getPassword());
dbUser.setToken(token);
Token格式
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIxLeeuoeeQhuWRmCIsImV4cCI6MTc0MjkyMTk5Mn0.PH2OJMzhqZFuJz-aW5nWfE5wZk9fbM-tgxPql1_NNVI"
JWT拦截器对所有访问的接口进行验证
通过webConfig做一层拦截器拦截所有的接口
@Configuration public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInterceptor()).addPathPatterns("/**")//校验规则所有接口.excludePathPatterns("/login","/register");//排除登录和注册接口}@Beanpublic JWTInterceptor jwtInterceptor(){return new JWTInterceptor();} }
JWT拦截器
/*** JWT拦截器* 做拦截器的实现* 对Token进行拦截并进一步解析Token、验证Token,看看Token是否是合法的*/ @Component public class JWTInterceptor implements HandlerInterceptor {@Resourceprivate UserService userService;@Resourceprivate ZuKeService zuKeService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1.从请求头拿到TokenString token=request.getHeader("token");if (StrUtil.isEmpty(token)){//如果没拿到,从参数中再拿一次token=request.getParameter("token");}//2.认证Tokenif (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 ("管理员".equals(role)){account=userService.selectById(userId);} else if ("租客".equals(role)) {account=zuKeService.selectById(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;} }
出现401错误,无权访问数据怎么办
在Vue的request.js的拦截器里面添加统一的请求头Token
request.js的代码
import axios from "axios"; import {ElMessage} from "element-plus";const request = axios.create({baseURL:'http://localhost:8080',//后端统一的请求地址timeout:30000 //后台接口时间 }) //request 拦截器 //可以自请求发送前对请求做一些处理 request.interceptors.request.use(config =>{//统一的数据传输格式为json,统一的编码utf-8config.headers['Content-Type']='application/json;charset=utf-8';//let user=JSON.parse(localStorage.getItem('pro1-user') || '{}');//config.headers['token']=user.token;// ✅ 安全获取 user(兼容 null 和异常情况)let user = {};try {const userStr = localStorage.getItem('pro1-user');user = userStr ? JSON.parse(userStr) : {};} catch (e) {console.error('解析 pro1-user 失败:', e);}// 仅当 token 存在时才添加到 headersif (user.token) {config.headers['token'] = user.token;} else {console.warn('Token 不存在,请求可能被后端拒绝');// 可选:跳转到登录页// window.location.href = '/login'; }return config; },error=>{return Promise.reject(error) }); //response拦截器 //可以在接口响应后统一处理结果 request.interceptors.response.use(response =>{let res=response.data;//兼容服务端返回的字符串数据if(typeof res === 'string'){//如果是string,转成jsonres = res ? JSON.parse(res) : res}if (res.code === '401'){ElMessage.error(res.msg);router.push('/login')}else {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
获取当前登录用户信息
@Component public class TokenUtil {@ResourceUserService userService;@ResourceZuKeService zuKeService;static UserService stasticUserService;static ZuKeService stasticZuKeService;/*** 生成 JWT 令牌*/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算法加密 }/*** 获取当前登录用户信息* @return*/public static Account getCurrentUser(){Account account=null;HttpServletRequest request=((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();String token=request.getHeader("token");if (StrUtil.isEmpty(token)){//如果没拿到,从参数中再拿一次token=request.getParameter("token");}//拿到Token载荷数据String audience = JWT.decode(token).getAudience().get(0);String[] split=audience.split("-");String userId=split[0];String role=split[1];if ("管理员".equals(role)){return stasticUserService.selectById(userId);}else if ("租客".equals(role)){return stasticZuKeService.selectById(userId);}return null;} }
在service方法里面获取当前登录用户的信息
Account currentUser=TokenUtil.getCurrentUser();