JWT工具类

迭代珊瑚
• 阅读 2611

工具开源地址

    欢迎大家搜索“小猴子的技术笔记”关注我的公众号,有问题可以及时和我交流。

    之前我们已经了解到了什么是JWT以及JWT的优点,那么怎么在项目中使用到JWT呢?首先我们需要在maven的项目中引入JWT的依赖:


<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
  <version>3.12.0</version>
</dependency>

    成功引入jar包之后就可以进行token的生成了。之后需要指定一个加密的算法,也就是需要你自己提供一个秘钥串来进行加密。你可以把它理解为之前做MD5加密的时候加上的盐值。

Algorithm algorithm = Algorithm.HMAC256("this is your secret")

    我们有十种算法可以选择:
JWT工具类
    然后我们就可以利用jar包中的方法,创建一个token并且附带上签名,之后就能够得到一个完整的token令牌。


public static void main(String[] args) {
    Algorithm algorithm = Algorithm.HMAC256("this is your secret");
    String token = JWT.create().sign(algorithm);
    System.out.println(token);
}
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.svmNHFYzrAj6USTjLekz3CTFyEdmpRkE8A8x3CbPe1Q

    这仅仅是一个简单的token的生成,有的时候我们还想在token中传递我们的信息,就可以使用下面这个方法:

public static void main(String[] args) {
    Algorithm algorithm = Algorithm.HMAC256("this is your secret");
    String token = JWT.create().withClaim("name", "小猴子").sign(algorithm);
    System.out.println(token);
}

    如果你有很多条件需要传递就可以“withClaim()”多个值。需要注意的是:这里请不要传递敏感的信息以免token被破解,信息泄露。

    我们在开发中一个token肯定不可能一直使用,一定有个过期时间。那么在JWT中怎么定义token的过期时间呢?JWT内置了为我们设置token的过期时间策略,官网给提供了一个“withExpireAt()”的方法。需要传递一个日期参数来指定过期时间。
JWT工具类

public static void main(String[] args) {
    Algorithm algorithm = Algorithm.HMAC256("this is your secret");
    JWTCreator.Builder builder = JWT.create().withClaim("name", "小猴子");
    String token = builder.withExpiresAt(new Date(System.currentTimeMillis() + 2000)).sign(algorithm);
    System.out.println(token);
}

    生成token:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5bCP54y05a2QIiwiZXhwIjoxNjEwODgzOTEzfQ.sAqi1xhajwKCxuv5sx8EwlcpbflsJs-k-67Nqr8PSYg

    上面我们自定义了过期的时间,是当前时间+2000毫秒之后过期,也就是2秒之后过期。那么怎么来查看token是否已经过期呢?我们需要用到token的校验:

public static void main(String[] args) {
    Algorithm algorithm = Algorithm.HMAC256("this is your secret");
    JWTVerifier verifier = JWT.require(algorithm).build();
    DecodedJWT decoded = verifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5bCP54y05a2QIiwiZXhwIjoxNjEwODgzOTEzfQ.sAqi1xhajwKCxuv5sx8EwlcpbflsJs-k-67Nqr8PSYg");
    System.out.println(decoded.getPayload());
}

    等待两秒之后在执行,你会发现它抛出如下的错误信息:

Exception in thread "main" com.auth0.jwt.exceptions.TokenExpiredException: The Token has expired on Sun Jan 17 19:45:13 CST 2021.
  at com.auth0.jwt.JWTVerifier.assertDateIsFuture(JWTVerifier.java:403)
  at com.auth0.jwt.JWTVerifier.assertValidDateClaim(JWTVerifier.java:394)
  at com.auth0.jwt.JWTVerifier.verifyClaimValues(JWTVerifier.java:314)
  at com.auth0.jwt.JWTVerifier.verifyClaims(JWTVerifier.java:303)
  at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:288)
  at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:271)
  at com.monkeybrother.jwt.utils.JwtUtil.main(JwtUtil.java:65)

    通过查看JWT的源码可以发现,JWT给我们提供了5中token校验的时候会抛出来的异常信息:
JWT工具类
    我们知道token保存在客户端,相比于传统的token过期删除token,JWT的过期时间是怎么控制的呢?它是将时间设置为一个"claim"然后在解析的时候解析这个“claim”通过拿到字段和当前时间进行比较。

    程序报异常是不够友好的,我们可以对异常进行捕获,然后自定义我们捕获到的异常信息。于是我们的校验token的方法可以进行更改成如下:

public static void main(String[] args) {
    try {
        Algorithm algorithm = Algorithm.HMAC256("this is your secret");
        JWTVerifier verifier = JWT.require(algorithm).build();
        DecodedJWT decoded = verifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5bCP54y05a2QIiwiZXhwIjoxNjEwODgzOTEzfQ.sAqi1xhajwKCxuv5sx8EwlcpbflsJs-k-67Nqr8PSYg");
    } catch (AlgorithmMismatchException e) {
        System.out.println("token算法不一致");
    } catch (InvalidClaimException e) {
        System.out.println("无效的token声明");
    } catch (JWTDecodeException e) {
        System.out.println("token解码异常");
    } catch (SignatureVerificationException e) {
        System.out.println("token签名无效");
    } catch (TokenExpiredException e) {
        System.out.println("token已过期");
    } catch (Exception e) {
        System.out.println("其他异常");
    }
}

    如果token校验合法,我们就可以从token中获取我们之前设置的“claim”:


DecodedJWT decodedJWT = JWT.require(algorithm).build().verify(token);
public static void main(String[] args) {
    Algorithm algorithm = Algorithm.HMAC256("this is your secret");
    JWTCreator.Builder builder = JWT.create().withClaim("name", "小猴子");
    String token = builder.withExpiresAt(new Date(System.currentTimeMillis() + 2000000)).sign(algorithm);
    DecodedJWT decodedJWT = JWT.require(algorithm).build().verify(token);
    System.out.println(decodedJWT.getClaim("name").asString());
}

    对于我们想要设置的“claim”总不能一个一个的添加吧,我们可以封装一个方法对我们想要添加的信息进行一次批量的添加。我这里给简单封装了一个工具类:

**
 * @Desc jwt工具类
 * @Author houry
 * @Date 2021/1/5 10:09
 **/
public class JwtUtil {
    /**
     * 秘钥:需要妥善保存,一旦泄露token有可能被破解
     */
    private static final String SECRET = "#$@!FX()!JF%JS$KLS*KFH##%#QPCIXMSJ";
    /**
     * 签名算法:推荐使用HMAC256
     */
    private static final Algorithm ALGORITHM = Algorithm.HMAC256(SECRET);

    /**
     * 设置默认过期时间 1000*60*60=3600000=1h
     */
    private static final Long EXPIRE_DATE = 3600000L;

    /**
     * 获取token信息
     *
     * @param claimMap 自定义的条件
     * @return token令牌
     */
    public static String getToken(Map<String, String> claimMap) {
        return getToken(claimMap, EXPIRE_DATE);
    }

    /**
     * @param claimMap 自定义条件
     * @param expire   过期时间 单位:毫秒
     * @return token令牌
     */
    public static String getToken(Map<String, String> claimMap, Long expire) {
        JWTCreator.Builder builder = JWT.create();
        claimMap.forEach(builder::withClaim);
        builder.withExpiresAt(new Date(System.currentTimeMillis() + expire));
        return builder.sign(ALGORITHM);
    }

    /**
     * 获取DecodedJWT
     *
     * @param token token令牌
     * @return DecodedJWT
     */
    public static DecodedJWT getDecodedJWT(String token) {
        return JWT.require(ALGORITHM).build().verify(token);
    }

    /**
     * 获取DecodedJWT
     *
     * @param algorithm 指定算法
     * @param token     token令牌
     * @return DecodedJWT
     */
    public static DecodedJWT getDecodedJWT(Algorithm algorithm, String token) {
        return JWT.require(algorithm).build().verify(token);
    }
}

    注意:这里仅仅是简简单单的介绍了如何生成token,用户可以自定义一个拦截器,对token进行拦截然后判断。对于每个用户的加密的算法,可以结合数据库,存储在数据库中这样每个人的加密算法就都不一样,不用担心一个token被破解所有的账户都会被破解。代码我已经开源,欢迎大家进行工具的补充和指正,后期我会结合SpringSecurity进行整合。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这