> 文档中心 > 原来这就叫JWT啊

原来这就叫JWT啊


一、JWT是什么?

JWT的全称为json web token。不要把它想得多么高深,其实就是一种生成token的方式。一般我们访问一个系统的流程就是:请求登录接口,该接口会返回一个token,请求其他接口都要带上token,token验证通过才能访问成功,而JWT可以理解为就是生成token的一种机制。

二、JWT怎么用?

1、添加jwt的依赖

<!-- JWT --><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version></dependency>

2、新建一个TokenService,用来生成token

@Servicepublic class TokenService {// token过期时间5分钟private static final long EXPIRE_TIME = (60 * 1000 * 5);public String getToken(User user) {return JWT.create()// 需要放入token中的信息.withAudience(user.getId())// 设置token过期时间.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRE_TIME))// 用户密码当作密钥.sign(Algorithm.HMAC256(user.getPassword()));}}

User类就是一个普通的pojo,这里就不把代码贴出来了。这个getToken方法表示将用户的密码作为密钥,把用户的id放进token中,设置token过期时间为5分钟。

3、新建两个注解,一个注解表示需要验证,另一个表示跳过验证

  • 需要验证:
//可以作用在方法,类和接口上@Target({ElementType.METHOD, ElementType.TYPE})//编译器会将SkipToken的信息保存在虚拟机中@Retention(RetentionPolicy.RUNTIME)public @interface NeedToken {// required 属性默认值为trueboolean required() default true;}
  • 跳过验证:
@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface SkipToken {boolean required() default true;}

4、新建一个AuthInterceptor类,用于拦截请求

public class AuthInterceptor implements HandlerInterceptor {@Autowiredprivate UserService userService;@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,Object object) {// 从 http 请求头中取出 tokenString token = httpServletRequest.getHeader("token");// 只拦截方法,不是方法直接返回trueif (!(object instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) object;Method method = handlerMethod.getMethod();// 有SkipToken注解的直接跳过认证if (method.isAnnotationPresent(SkipToken.class)) {SkipToken skipToken = method.getAnnotation(SkipToken.class);if (skipToken.required()) {return true;}}// 有NeedToken注解的就进行认证if (method.isAnnotationPresent(NeedToken.class)) {NeedToken needToken = method.getAnnotation(NeedToken.class);if (needToken.required()) {if (token == null) {throw new RuntimeException("无token,请重新登录");}// 获取 token 中的 userIdString userId;try {userId = JWT.decode(token).getAudience().get(0);} catch (JWTDecodeException j) {throw new RuntimeException("401");}// 根据userId查询数据库User user = userService.findUserById(userId);if (user == null) {throw new RuntimeException("用户不存在,请重新登录");}// 用查出来的user的密码去校验tokenJWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();try {      // 没发生异常就表示校验通过jwtVerifier.verify(token);} catch (JWTVerificationException e) {throw new RuntimeException("401");}return true;}}return true;}@Overridepublic void postHandle(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse, Object o,ModelAndView modelAndView) {}@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o, Exception e) {}}

这个拦截器的处理逻辑就是:

  • 只拦截方法,如果不是方法,就放行;
  • 如果拦截的方法有@SkipToken注解,放行;
  • 如果拦截的方法有@NeedToken注解,则需要验证token;
  • 取出请求头中的token,拿出token中的userId,根据此userId去数据库查询对应的记录;
  • 再将查出来的user的password去验证token,验证成功则放行;
  • 如果没有@NeedToken也没有@SkipToken注解的,也放行。

5、新建一个InterceptorConfig类,将我们上面写的拦截器配置到spring容器中去

@Configurationpublic class InterceptorConfig implements WebMvcConfigurer {@Override    public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authInterceptor())  .addPathPatterns("/**");}    @Bean    public AuthInterceptor authInterceptor() { return new AuthInterceptor();    }}

6、在controller中的用法

@RestController@RequestMapping("api")public class UserController {@Autowired    private UserService userService;    @Autowired    private TokenService tokenService;@SkipToken    @PostMapping("/user")    public JsonResult login(User user){ User dbUser = userService.findForLogin(user); if (dbUser == null){     return new JsonResult(200, "用户名或密码错误", null); } else {     String token = tokenService.getToken(dbUser);     Map<String, Object> resultMap = new HashMap<>();     resultMap.put("token", token);     resultMap.put("user", dbUser);     return new JsonResult(200, "登录成功", resultMap); }    } @NeedToken    @GetMapping("/getMessage")    public String getMessage(){ return "你已通过验证";    } @SkipToken    @GetMapping("/noToken")    public String noToken() {    return "无需token访问";    }}

以上就是JWT的用法,其实在实际生产中一般会配合shiro使用。