SpringBoot Vue使用Jwt实现简单的权限管理
为实现Jwt简单的权限管理,我们需要用Jwt工具来生成token,也需要用Jwt来解码token,同时需要添加Jwt拦截器来决定放行还是拦截。下面来实现:
1、gradle引入Jwt、hutool插件
implementation 'com.auth0:java-jwt:3.10.3'
implementation 'cn.hutool:hutool-all:5.3.7'
2、Jwt工具类,提供静态方法生成token,和根据请求携带的token查找user信息
package com.zzz.simple_blog_backend.utils;
import ......
@Component
public class JwtTokenUtils {
@Autowired
private UserService userService;
private static UserService userServiceStatic;
@PostConstruct//在spring容器初始化后执行该方法
public void setUserService() {
userServiceStatic = userService;
}
//生成Token
public static String genToken(String userId,String passwordSign) {
return JWT.create().withAudience(userId)//放入载荷
.withExpiresAt(DateUtil.offsetHour(new Date(), 2))//2小时后过期
.sign(Algorithm.HMAC256(passwordSign));//密码签名作为密钥
}
//通过token获取当前登录用户信息
public static User getCurrentUser() {
String token = null;
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
//1、获取token
token = request.getHeader("token");
if (StrUtil.isBlank(token)) {
token = request.getParameter("token");
}
if (StrUtil.isBlank(token)) {
throw new RuntimeException("没有token,请重新登录");
}
String userId;
User user;
try {
userId = JWT.decode(token).getAudience().get(0);
} catch (Exception e) {
throw new RuntimeException("token验证失败,请重新登录!!!");
}
user = userServiceStatic.findById(Integer.parseInt(userId));
if(user==null) {
throw new RuntimeException("用户id不存在,请重新登录!!!");
}
//3、用密码签名,解码判断token
try {
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new CustomException(001, "token验证失败,请重新登录!!!");
}
return user;
}
}
3、Jwt拦截器
SpringBoot添加拦截器,excludePathPatterns
可以指定不拦截的页面,RestController
指定了请求前缀,控制器类要用@RestController
代替@Controller
,addInterceptor
添加了jwtInterceptor
拦截器。
package com.zzz.simple_blog_backend.config;
import ...
@Configuration
public class WebConfig implements WebMvcConfigurer{
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
//指定restcontroller统一接口前缀
configurer.addPathPrefix("/api", clazz -> clazz.isAnnotationPresent(RestController.class));
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 加自定义拦截器 给特定请求放行
registry.addInterceptor(jwtInterceptor).addPathPatterns("/api/**")
.excludePathPatterns("/api/user/login","/api/user/register");
}
}
仔细的童靴会发现JwtTokenUtils.getCurrentUser()
方法和JwtInterceptor
的拦截方法很像,主要区别就在if(user.getRole()!=0)
的判断。所以JwtInterceptor
只会给管理员放行,如果需要给普通用户放行而未登录用户不放行,那请求路径先添加到excludePathPatterns
,并且控制类对应的响应方法第一句就先调用JwtTokenUtils.getCurrentUser()
判断是否用户已登录。
package com.zzz.simple_blog_backend.config;
import ......
@Component
public class JwtInterceptor implements HandlerInterceptor{
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//1、获取token
String token = request.getHeader("token");
if (StrUtil.isBlank(token)) {
token = request.getParameter("token");
}
if (StrUtil.isBlank(token)) {
throw new RuntimeException("没有token,请重新登录");
}
//2、开始认证 解码token,获得userId
String userId;
User user;
try {
userId = JWT.decode(token).getAudience().get(0);
} catch (Exception e) {
throw new RuntimeException("token验证失败,请重新登录!!!");
}
user = userService.findById(Integer.parseInt(userId));
if(user==null) {
throw new RuntimeException("用户id不存在,请重新登录!!!");
}
if(user.getRole()!=0) {
throw new RuntimeException("非管理员账号,无权访问!!!");
}
//3、用密码签名,解码判断token
try {
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new RuntimeException("token验证失败,请重新登录!!!");
}
//token验证成功,放行
return true;
// return HandlerInterceptor.super.preHandle(request, response, handler);
}
}
4、前后端登录操作
登录后 后端返回带token不带密码的user数据
@PostMapping("user/login")
@ResponseBody
public CommonResult<Object> login(@RequestBody User user){
user = userService.findByUsernameAndPassword(user);
if (user == null) {
return CommonResult.failed(001, Message.createMessage("用户名或密码错误!!!"));
} else {
//生成用户对应的Token
String token = JwtTokenUtils.genToken(user.getId().toString(), user.getPassword());
user.setToken(token);
//不传输密码
user.setPassword("");
return CommonResult.success(user);
}
}
前端保存带token的user
//axios的post请求成功后操作
localStorage.setItem("user",JSON.stringify(response.data.data));//保存用户信息
5、前端每次请求都携带token信息
假设已安装axios,Axios.interceptors.request
拦截用户所有请求,添加token信息后再发送请求,这样后端就可以判断了。
import Axios from 'axios'
Vue.prototype.$http = Axios;
//添加向后端发起请求的服务器地址前缀
Axios.defaults.baseURL=AIOS_BASE_URL; // "http://127.0.0.1/api"
//设置请求超时时间
Axios.defaults.timeout=5000;
//axios拦截器
//对接口request拦截
Axios.interceptors.request.use(function(config){
//发起增删改查请求时,带上token认证
var user = localStorage.getItem("user");
if(user){
config.headers["token"] = JSON.parse(user).token;
}
return config;
})
//携带证书 session id 跨域请求的话需要
Axios.defaults.withCredentials = true
总结
Jwt实现权限管理的原理是登录成功后 后端端生成token密钥,随着用户信息发送给客户端,客户端接受并保存信息到本地localStorage。以后每次需要权限验证时,根据客户端返回的携带token信息,后端进行拦截并解码校验,通过则放行,否则抛异常。如果要抛异常时,返回错误信息给前端,请看链接。
原文地址:https://blog.csdn.net/heiye_007/article/details/140709376
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!