1. 引入JWT依赖,由于是基于Java,所以需要的是java-jwt
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version>
</dependency>
  1. 自定义注解用于判断是否需要验证
  • 用来跳过验证的PassToken
 @Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface PassToken {boolean required() default true;}
  • 需要登录才能进行操作的注解UserLoginToken
@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface UserLoginToken {boolean required() default true;}

@Target:注解的作用目标

  • @Target(ElementType.TYPE)——接口、类、枚举、注解
  • @Target(ElementType.FIELD)——字段、枚举的常量
  • @Target(ElementType.METHOD)——方法
  • @Target(ElementType.PARAMETER)——方法参数
  • @Target(ElementType.CONSTRUCTOR) ——构造函数
  • @Target(ElementType.LOCAL_VARIABLE)——局部变量
  • @Target(ElementType.ANNOTATION_TYPE)——注解
  • @Target(ElementType.PACKAGE)——包
    @Retention:注解的保留位置
    RetentionPolicy.SOURCE:这种类型的Annotations只在源代码级别保留,编译时就会被忽略,在class字节码文件中不包含。 RetentionPolicy.CLASS:这种类型的Annotations编译时被保留,默认的保留策略,在class文件中存在,但JVM将会忽略,运行时无法获得。 RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
    @Document:说明该注解将被包含在javadoc中
    @Inherited:说明子类可以继承父类中的该注解

3.编写token的生成方法

  • 生成不携带自定义信息的 JWT token
  1. 构建头部信息
 Map<String, Object> map = new HashMap<String, Object>();map.put("alg", "HS256");map.put("typ", "JWT");
  1. 构建密钥信息
 Algorithm algorithm = Algorithm.HMAC256("secret");

Algorithm.HMAC256(): 使 HS256 生token,唯一密钥可以保存在服务端。“secret” 为相应的密钥

  1. 我们通过定义注册和自定义声明 并组合头部信息和密钥信息生成jwt token
 String token = JWT.create().withHeader(map)// 设置头部信息 Header .withIssuer("SERVICE")//设置 载荷 签名是有谁生成 例如 服务器.withSubject("this is test token")//设置 载荷 签名的主题// .withNotBefore(new Date())//设置 载荷 定义在什么时间之前,该jwt都是不可用的..withAudience("APP")//设置 载荷 签名的观众 也可以理解谁接受签名的.withIssuedAt(nowDate) //设置 载荷 生成签名的时间.withExpiresAt(expireDate)//设置 载荷 签名过期的时间.sign(algorithm);//签名 Signature
  • 生成携带自定义信息的 JWT token
    自定义信息通过 withClaim 方法进行添加,具体操作如下:
JWT.create().withHeader(map).withClaim("key", "value")
  1. 验证 JWT token
  • 构建密钥信息
  Algorithm algorithm = Algorithm.HMAC256("secret");
  • 通过密钥信息和签名的发布者的信息生成 JWTVerifier (JWT验证类)
 JWTVerifier verifier = JWT.require(algorithm).withIssuer("SERVICE").build();

不添加 .withIssuer(“SERVICE”) 也是可以获取 JWTVerifier 。

  • 通过 JWTVerifier 的verify获取 token中的信息。
DecodedJWT jwt = verifier.verify(token);

如下面代码所示就可以获取到我们之前生成 token 的 签名的主题,观众 和自定义的声明信息。

 String subject = jwt.getSubject();//获得签名主题List<String> audience = jwt.getAudience();//获得签名接收方Map<String, Claim> claims = jwt.getClaims();//获得自定义信息for (Entry<String, Claim> entry : claims.entrySet()) {String key = entry.getKey();Claim claim = entry.getValue();System.out.println("key:"+key+" value:"+claim.asString());}
  1. 编写拦截器 interceptor
public class AuthenticationInterceptor implements HandlerInterceptor {@AutowiredUserService userService;@Overridepublic boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object object) throws IOException {String token = req.getHeader("token");// 从 http 请求头中取出 token// 如果不是映射到方法直接通过if(!(object instanceof HandlerMethod)){return true;}//获得控制器函数所在的控制器类HandlerMethod handlerMethod = (HandlerMethod)object;//获得控制器函数Method method = handlerMethod.getMethod();//获得控制器函数所在的控制器类的ClassClass controllerClass = handlerMethod.getBean().getClass();//检查类中是否有跳过认证的注解if(controllerClass.isAnnotationPresent(PassToken.class)){PassToken passToken = (PassToken) controllerClass.getAnnotation(PassToken.class);if (passToken.required()) {return true;}}//检查方法是否有passtoken注释,有则跳过认证if (method.isAnnotationPresent(PassToken.class)) {PassToken passToken = method.getAnnotation(PassToken.class);if (passToken.required()) {return true;}}//判断类中是否有登陆注解if(controllerClass.isAnnotationPresent(UserLoginToken.class)){UserLoginToken userLoginToken = (UserLoginToken);controllerClass.getAnnotation(UserLoginToken.class);//验证tokenneedUserLogin(userLoginToken, token);}//判断方法中是否有登陆的注解if(method.isAnnotationPresent(UserLoginToken.class)){UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);//验证tokenneedUserLogin(userLoginToken, token);}return true;}//验证注解的函数public boolean needUserLogin(UserLoginToken userLoginToken, String token){if(userLoginToken.required()){//需要验证if(token == null){throw new RuntimeException("无token, 请重新登陆");}String un;try{//获取签名接受方un = JWT.decode(token).getAudience().get(0);}catch (JWTDecodeException j) {throw new RuntimeException("401");}//通过用户名获取用户信息User user = userService.findUserByUn(un);if(user == null){throw new RuntimeException("用户不存在,请重新登陆");}// 通过生成算法及密钥生成 token验证类JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPd())).build();try {//验证 token,验证错误或token超时会抛出异常jwtVerifier.verify(token);} catch (JWTVerificationException e) {throw new RuntimeException("401");}return true;}return true;}
}

实现一个拦截器就需要实现HandlerInterceptor接口

HandlerInterceptor接口主要定义了三个方法

  • boolean preHandle (): 预处理回调方法,实现处理器的预处理,第三个参数为响应的处理器,自定义Controller,返回值为true表示继续流程(如调用下一个拦截器或处理器)或者接着执行 postHandle()和afterCompletion();false表示流程中断,不会继续调用其他的拦截器或处理器,中断执行。
  • void postHandle(): 后处理回调方法,实现处理器的后处理(DispatcherServlet进行视图返回渲染之前进行调用),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
  • void afterCompletion(): 整个请求处理完毕回调方法,该方法也是需要当前对应的Interceptor的preHandle()的返回值为true时才会执行,也就是在DispatcherServlet渲染了对应的视图之后执行。用于进行资源清理。整个请求处理完毕回调方法。如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中
    主要流程:
    1.从 http 请求头中取出 token
    2.判断是否映射到方法或控制器类
    3.检查是否有passtoken注释,有则跳过认证
    4.检查有没有需要用户登录的注解,有则需要取出并验证
    5.认证通过则可以访问,不通过会报相关错误信息

6.注册拦截器

在配置类上添加了注解@Configuration,标明了该类是一个配置类并且会将该类作为一个SpringBean添加到IOC容器内

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(authenticationInterceptor()).addPathPatterns("/**");    // 拦截所有请求,通过判断是否有 @UserLoginToken 注解 决定是否需要登录}@Beanpublic AuthenticationInterceptor authenticationInterceptor() {return new AuthenticationInterceptor();}
}

总结

JWT 就是一个生成 Token 的工具,如果不使用 JWT 我们也可以根据自己加密规则生成 Token。只不过 JWT 规范了生成 Token 定义了一个标准而已。JWT 的核心的功能就是:生成Token、解析Token。

参考博客:

  • https://blog.csdn.net/ljk126wy/article/details/82751787
  • https://www.jianshu.com/p/e88d3f8151db

JAVA 实现 JWT相关推荐

  1. JAVA 安全-JWT 安全及预编译 CASE 注入等

    JAVA 安全-JWT 安全及预编译 CASE 注入等 SQL Injection(mitigation) 利用 session 防御 参数绑定方式&order by 绕过 实例 什么是 JW ...

  2. Java使用JWT开源库

    一.JWT简介 JWT官方文档: https://jwt.io/ https://jwt.io/introduction/ 1.什么是JWT 图片来自官方文档,解释的很清楚了. 通俗地说,JWT的本质 ...

  3. 浅析JWT| JWT是啥子,Java构建JWT

    小声bbb 说到系统的安全识别,记得自己第一个项目,用的就是session,用户登录进来以后,给他session标记登录,记录id进去,轻轻松松,设计的操作也很简单,类似操作HashMap. 这大概也 ...

  4. java中JWT设置过期时间_JWT(JSON Web Token)自动延长到期时间

    jwt-autorefresh 如果您使用的是节点(React / Redux / Universal JS),则可以安装 npm i -S jwt-autorefresh . 此库根据用户计算的访问 ...

  5. 解决Java中JWT的token认证接口测试时:认证失败,无法访问系统资

    步骤: 登录页面后,右击检查->network->XHR->复制Authorization的内容 粘贴到postman中安全认证哪里,类型下载token.

  6. java jwt 验证_教程:用Java创建和验证JWT

    java jwt 验证 "我喜欢编写身份验证和授权代码." 〜从来没有Java开发人员. 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多 ...

  7. 教程:用Java创建和验证JWT

    "我喜欢编写身份验证和授权代码." 〜从来没有Java开发人员. 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证. Java ...

  8. Web安全通讯之JWT的Java实现

    上篇文章中目的是介绍 Json Web Token(以下简称 jwt) ,由于我对 Java 比较熟悉就介绍 Java 服务端 的实现方式,其他语言原理是相同的哈~ PS:如果不清楚JWT,请先看 & ...

  9. 【应用安全】 使用Java创建和验证JWT

    Java对JWT(JSON Web Tokens)的支持过去需要大量的工作:广泛的自定义,几小时的解析依赖关系,以及仅用于组装简单JWT的代码页.不再! 本教程将向您展示如何使用现有的JWT库来做两件 ...

最新文章

  1. 在BAE搭建的Django中实现图片上传并用jquery预览图片
  2. [IOI2008] Fish 鱼
  3. friend keyword 对于模板 并不只不过友元!!!
  4. Kubernetes 入门必备云原生发展简史
  5. 重复 桂林电子科技大学第三届ACM程序设计竞赛
  6. 程序设计中的驼峰原则
  7. [转载]生活在 Emacs 中
  8. 如何让caffe读取多通道图片(=4)
  9. SharedPreferences的制作
  10. yagmail发送带图片和链接的邮件
  11. LaTex 数学之数学字体
  12. 图书馆图书借阅登记微信小程序管理软件系统开发制作
  13. java计算机毕业设计BS景区票务管理系统设计与实现源码+mysql数据库+系统+lw文档+部署
  14. Emlog大表哥资源网模板
  15. BEVFormer论文解析
  16. php 匿名函数 递归,匿名函数,lambda_C++ lambda 递归调用,匿名函数,lambda,c++ - phpStudy...
  17. Python代码中的三大常见“愚形”,你中招了吗?
  18. 复现《nature communications》图表(一):一模一样的Figure1
  19. 广点通sdk接入(作为广告主身份)
  20. 5种创建Dataframe方法

热门文章

  1. 2019 ICPC World Finals Problem J. Miniature Golf
  2. Acwing 1072. 树的最长路径
  3. 牛客题霸 [两个链表生成相加链表] C++题解/答案
  4. 2021牛客NOIP提高组OI赛前模拟赛第一场T2——牛牛和数组操作(区间dp)
  5. jzoj6312-Lottery【dp,前缀和】
  6. 【dfs】树上游戏(P2664)
  7. K8S Learning(4)——Namespace
  8. Druid SQL查询数据timeStamp时区问题
  9. Java面试,如何在短时间内做突击
  10. JavaScript学习总结(七)——JavaScript函数(function)