1.使用JWT生成token
第一步:引入依赖
<!-- JWT --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version> </dependency>
第二步:创建工具类
在until包下创建TokenUntil类,用于生成token
利用id,和password作为参数生成token
JWt为这个包下的对象
import com.auth0.jwt.JWT;
package com.example.mybatis_plus_generator.untils;import cn.hutool.core.date.DateUtil;import com.auth0.jwt.JWT;import com.auth0.jwt.algorithms.Algorithm;import org.springframework.stereotype.Component;import java.util.Date;/** * @author shkstart * @create 2023-08-06-13:51 */@Componentpublic class TokenUtils { //获取token的静态方法 public static String getToken(String userId,String password){ return JWT.create().withAudience(userId)// 将 user id 保存到 token 里面,作为载荷 .withExpiresAt(DateUtil.offsetHour(new Date(), 2))// 2小时后token过期 .sign(Algorithm.HMAC256(password));// 以 password 作为 token 的密钥 }}
第三步:token使用
在向前端返回的数据对象中添加token属性
是serve层中调用工具类方法将生成的token放到返回的数据中
注意:这里获取到的id是integer类型,需要用toString进行类型转换
第四步:测试接口
2.通过验证token的拦截器
思路:建立一个统一的拦截器配置类,自己定义一个验证token的配置类。把它放到拦截器类中
知识储备:
关于WebMvcConfigurationSupport类
是Spring MVC提供的一个配置类,用于扩展和自定义Spring MVC的行为。通过继承该类并重写相应的方法,我们可以实现定制化的配置,包括添加拦截器、配置视图解析器、自定义消息转换器等
关于HandlerInterceptor接口
用于拦截请求并对请求进行预处理和后处理。它允许开发人员在请求到达处理器方法之前和之后执行一些自定义的逻辑操作。
HandlerInterceptor接口定义了三个方法:
preHandle:在处理器方法执行之前被调用。可以在该方法中进行一些预处理操作,如身份验证、权限检查、日志记录等。如果返回true,则继续执行后续的拦截器和处理器方法;如果返回false,则请求被拦截,后续的拦截器和处理器方法将不会被执行。
postHandle:在处理器方法执行之后、视图渲染之前被调用。可以在该方法中对响应进行一些后处理操作,如修改视图数据、添加公共模型属性等。
afterCompletion:在整个请求完成之后被调用,即视图渲染完成后。可以在该方法中处理一些释放资源的操作或执行一些日志记录等。
我们可以创建自定义的HandlerInterceptor实现类来实现上述方法,并将其注册到Spring MVC的配置中,以便拦截和处理请求。在Spring MVC的配置中,可以通过实现WebMvcConfigurer接口的addInterceptors方法来注册自定义的HandlerInterceptor。
通过使用HandlerInterceptor,我们可以实现一些与请求和响应相关的公共逻辑和功能,如身份验证、日志记录、参数解析、跨域处理等。拦截器提供了一种灵活的方式来对请求进行拦截和处理,帮助开发人员实现系统层面的功能和逻辑。
第一步:创建统一的拦截器类
在config报下建立InterceptorConfig类
该类需要加上@Configuration注解并基础WebMvcConfigurationSupport类
@Configurationpublic class InterceptorConfig extends WebMvcConfigurationSupport {}
第二步:建立验证token的类
在config.interceptor包写建立JwtInterceptor类用于验证token,继承接口HandlerInterceptor表示为拦截器类
重写preHandler,设置规则
package com.example.mybatis_plus_generator.config.interceptor;import com.auth0.jwt.JWT;import com.auth0.jwt.JWTVerifier;import com.auth0.jwt.algorithms.Algorithm;import com.example.mybatis_plus_generator.common.Constants;import com.example.mybatis_plus_generator.entity.User;import com.example.mybatis_plus_generator.exception.LoginException;import com.example.mybatis_plus_generator.service.IUserService;import org.apache.ibatis.logging.LogException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/** * @author shkstart * @create 2023-08-06-14:38 *///注入spring容器中,方便被调用@Componentpublic class JwtInterceptor implements HandlerInterceptor { //注入service用于验证对象 @Autowired private IUserService userService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { //在请求头中获取token String token = request.getHeader("token"); //若为空则抛出异常 if(token == null){ throw new LoginException(Constants.CODE_401,"token为空"); } //获取token中的id String userId; try { userId = JWT.decode(token).getAudience().get(0); }catch (Exception e){ throw new LoginException(Constants.CODE_500,"该token不正确"); } //判断该id的用户是否存在 User user = userService.getById(userId); if(user == null){ throw new LoginException(Constants.CODE_500,"该用户已经不存在"); } //核心:进行验证 JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build(); try { jwtVerifier.verify(token); }catch (Exception e){ throw new LoginException(Constants.CODE_500,"验证token时出错"); } //没问题返回true return true; }}
第三步:引入统一的拦截器类
@Configurationpublic class InterceptorConfig extends WebMvcConfigurationSupport { @Autowired JwtInterceptor jwtInterceptor; //增加拦截的规则 @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor)//将自己写好的拦截类放进来 .addPathPatterns("/**")//拦截所有 .excludePathPatterns("/user/login", "/user/register");//这两个放行 }}
第四步:测试
有token时查出
token值不正确时
3.通过token获取该用户的信息
把这个功能放到包装类中
思路:在until包下的TokenUntil写创建静态getCurrentUser方法,用于方便获取user信息
@Componentpublic class TokenUtils { private static IUserService staticUserService; @Resource private IUserService userService; @PostConstruct public void setUserService() { staticUserService = userService; } /** * 获取当前登录的用户信息 * * @return user对象 */ public static User getCurrentUser() { try { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String token = request.getHeader("token"); if (StrUtil.isNotBlank(token)) { String userId = JWT.decode(token).getAudience().get(0); return staticUserService.getById(Integer.valueOf(userId)); } } catch (Exception e) { return null; } return null; }}