SpringBoot Vue使用Jwt实现简单的权限管理

avatar
作者
猴君
阅读量:0

为实现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代替@ControlleraddInterceptor添加了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信息,后端进行拦截并解码校验,通过则放行,否则抛异常。如果要抛异常时,返回错误信息给前端,请看链接

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!