1. 对之前的代码改造,之前将user存储到sessionStorage,改成存储到localStorage,全局搜索修改
之前Result.code等于0代表success,改成200代表success, vue文件全局搜索修改
一、前端部分
1. 改造request.js,登录时将user已经存储到localStorage里,这里将user获取到,将user里的token放到请求头,后台根据请求头里的token进行校验
2. 后台token校验不通过,返回401,这时重定向到登录页
3. 修改退出系统按钮,退出时清空token和用户信息
二、后端部分
1. pom.xml 里引入java-jwt包
2. 创建 com/example/demo/common/JwtInterceptor.java 文件,内容是拦截规则
package com.example.demo.common; import cn.hutool.core.util.StrUtil; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.exceptions.JWTVerificationException; import com.example.demo.entity.User; import com.example.demo.exception.ServiceException; import com.example.demo.mapper.UserMapper; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; public class JwtInterceptor implements HandlerInterceptor { @Resource private UserMapper userMapper; public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler){ String token = request.getHeader("token"); // header里面传的参数 if (StrUtil.isBlank(token)){ token = request.getParameter("token"); // url参数 } // 方法上有AuthAccess注解时,直接返回true,即取消拦截,直接通过 if (handler instanceof HandlerMethod) { AuthAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class); if (annotation != null) { return true; } } // 执行认证 if (StrUtil.isBlank(token)) { throw new ServiceException("401", "请登录"); //401 权限错误 } // 获取token中的userId String userID; try { userID = JWT.decode(token).getAudience().get(0); // JWT.decode(token) 解码 } catch (JWTDecodeException e) { throw new ServiceException("401", "请登录"); } // 根据token中的userId查询数据库 User user = userMapper.selectById(Integer.valueOf(userID)); if (user == null) { throw new ServiceException("401","请登录"); //权限错误 } // 通过用户密码加密后生成一个验证器 JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build(); try { jwtVerifier.verify(token); // 验证token } catch (JWTVerificationException e) { throw new ServiceException("401", "请登录"); } return true; } }
3. 创建 com/example/demo/common/config/InterceptorConfig.java 文件,将上一步自定义的 JwtInterceptor 拦截规则传入,使规则生效,定义拦截路径和不拦截路径
package com.example.demo.common.config; import com.example.demo.common.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.WebMvcConfigurationSupport; @Configuration public class InterceptorConfig extends WebMvcConfigurationSupport { protected void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor(jwtInterceptor()) //配置jwt的拦截器规则,传入JwtInterceptor自定义的规则 .addPathPatterns("/**") //拦截所有的请求路径 .excludePathPatterns("/user/login","/files/*"); //将特定请求取消拦截,也可以通过AuthAccess注解实现 super.addInterceptors(registry); } @Bean public JwtInterceptor jwtInterceptor() { return new JwtInterceptor(); } }
3. 创建 com/example/demo/exception/ServiceException.java,拦截成功时会抛出 ServiceException 异常,这是个自定义的异常
package com.example.demo.exception; import lombok.Getter; @Getter public class ServiceException extends RuntimeException { private final String code; public ServiceException(String msg){ super(msg); this.code = "500"; } public ServiceException(String code,String msg){ super(msg); this.code = code; } }
4. 创建com/example/demo/exception/GlobalException.java,定义 抛出 ServiceException 异常时进行的处理,返回Result
package com.example.demo.exception; import com.example.demo.common.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()); } }
5. 第二种 取消拦截的方式,创建 com/example/demo/common/AuthAccess.java 注解
package com.example.demo.common; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AuthAccess { }
在方法上使用这个注解,拦截规则里获取 方法上的这个注解,如果获取到就取消拦截
6.user实体类增加token属性
7.改造登录方法,账号密码校验不通过时抛出 ServiceException 异常,账号密码正确时,生成token,存储到user里返回
测试:
登录时不进入拦截器,登录成功后跳转到用户管理,查询全部用户,这时跳转到拦截器,可以看到token已经生成并由前端传到后端
页面本地存储里也有token
标签:15,springboot,demo,JWT,token,ServiceException,import,com,example From: https://www.cnblogs.com/xiexieyc/p/18338722