以前一直使用的是jjwt这个JWT库,虽然小巧够用, 但对JWT的一些细节封装的不是很好。最近发现了一个更好用的JWT库nimbus-jose-jwt,简单易用,API非常易于理解,对称加密和非对称加密算法都支持,推荐给大家!

简介

nimbus-jose-jwt是最受欢迎的JWT开源库,基于Apache 2.0开源协议,支持所有标准的签名(JWS)和加密(JWE)算法。

JWT概念关系

这里我们需要了解下JWT、JWS、JWE三者之间的关系,其实JWT(JSON Web Token)指的是一种规范,这种规范允许我们使用JWT在两个组织之间传递安全可靠的信息。而JWS(JSON Web Signature)和JWE(JSON Web Encryption)是JWT规范的两种不同实现,我们平时最常使用的实现就是JWS。

使用

接下来我们将介绍下nimbus-jose-jwt库的使用,主要使用对称加密(HMAC)和非对称加密(RSA)两种算法来生成和解析JWT令牌。

对称加密(HMAC)

对称加密指的是使用相同的秘钥来进行加密和解密,如果你的秘钥不想暴露给解密方,考虑使用非对称加密。

  • 要使用nimbus-jose-jwt库,首先在pom.xml添加相关依赖;
<dependency>    <groupId>com.nimbusdsgroupId>    <artifactId>nimbus-jose-jwtartifactId>    <version>8.16version>dependency>
  • 创建JwtTokenServiceImpl作为JWT处理的业务类,添加根据HMAC算法生成和解析JWT令牌的方法,可以发现nimbus-jose-jwt库操作JWT的API非常易于理解;
/** * Created by macro on 2020/6/22. */@Servicepublic class JwtTokenServiceImpl implements JwtTokenService {    @Override    public String generateTokenByHMAC(String payloadStr, String secret) throws JOSEException {        //创建JWS头,设置签名算法和类型        JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.HS256).                type(JOSEObjectType.JWT)                .build();        //将负载信息封装到Payload中        Payload payload = new Payload(payloadStr);        //创建JWS对象        JWSObject jwsObject = new JWSObject(jwsHeader, payload);        //创建HMAC签名器        JWSSigner jwsSigner = new MACSigner(secret);        //签名        jwsObject.sign(jwsSigner);        return jwsObject.serialize();    }

    @Override    public PayloadDto verifyTokenByHMAC(String token, String secret) throws ParseException, JOSEException {        //从token中解析JWS对象        JWSObject jwsObject = JWSObject.parse(token);        //创建HMAC验证器        JWSVerifier jwsVerifier = new MACVerifier(secret);        if (!jwsObject.verify(jwsVerifier)) {            throw new JwtInvalidException("token签名不合法!");        }        String payload = jwsObject.getPayload().toString();        PayloadDto payloadDto = JSONUtil.toBean(payload, PayloadDto.class);        if (payloadDto.getExp() new Date().getTime()) {            throw new JwtExpiredException("token已过期!");        }        return payloadDto;    }}
  • 创建PayloadDto实体类,用于封装JWT中存储的信息;
/** * Created by macro on 2020/6/22. */@Data@EqualsAndHashCode(callSuper = false)@Builderpublic class PayloadDto {    @ApiModelProperty("主题")    private String sub;    @ApiModelProperty("签发时间")    private Long iat;    @ApiModelProperty("过期时间")    private Long exp;    @ApiModelProperty("JWT的ID")    private String jti;    @ApiModelProperty("用户名称")    private String username;    @ApiModelProperty("用户拥有的权限")    private List authorities;}
  • JwtTokenServiceImpl类中添加获取默认的PayloadDto的方法,JWT过期时间设置为60min
/** * Created by macro on 2020/6/22. */@Servicepublic class JwtTokenServiceImpl implements JwtTokenService {    @Override    public PayloadDto getDefaultPayloadDto() {        Date now = new Date();        Date exp = DateUtil.offsetSecond(now, 60*60);        return PayloadDto.builder()                .sub("macro")                .iat(now.getTime())                .exp(exp.getTime())                .jti(UUID.randomUUID().toString())                .username("macro")                .authorities(CollUtil.toList("ADMIN"))                .build();    }}
  • 创建JwtTokenController类,添加根据HMAC算法生成和解析JWT令牌的接口,由于HMAC算法需要长度至少为32个字节的秘钥,所以我们使用MD5加密下;
/** * JWT令牌管理Controller * Created by macro on 2020/6/22. */@Api(tags = "JwtTokenController", description = "JWT令牌管理")@Controller@RequestMapping("/token")public class JwtTokenController {

    @Autowired    private JwtTokenService jwtTokenService;

    @ApiOperation("使用对称加密(HMAC)算法生成token")    @RequestMapping(value = "/hmac/generate", method = RequestMethod.GET)    @ResponseBody    public CommonResult generateTokenByHMAC() {        try {            PayloadDto payloadDto = jwtTokenService.getDefaultPayloadDto();            String token = jwtTokenService.generateTokenByHMAC(JSONUtil.toJsonStr(payloadDto), SecureUtil.md5("test"));            return CommonResult.success(token);        } catch (JOSEException e) {            e.printStackTrace();        }        return CommonResult.failed();    }

    @ApiOperation("使用对称加密(HMAC)算法验证token")    @RequestMapping(value = "/hmac/verify", method = RequestMethod.GET)    @ResponseBody    public CommonResult verifyTokenByHMAC(String token) {        try {            PayloadDto payloadDto  = jwtTokenService.verifyTokenByHMAC(token, SecureUtil.md5("test"));            return CommonResult.success(payloadDto);        } catch (ParseException | JOSEException e) {            e.printStackTrace();        }        return CommonResult.failed();

    }}
  • 调用使用HMAC算法生成JWT令牌的接口进行测试;

  • 调用使用HMAC算法解析JWT令牌的接口进行测试。

非对称加密(RSA)

非对称加密指的是使用公钥和私钥来进行加密解密操作。对于加密操作,公钥负责加密,私钥负责解密,对于签名操作,私钥负责签名,公钥负责验证。非对称加密在JWT中的使用显然属于签名操作。

  • 如果我们需要使用固定的公钥和私钥来进行签名和验证的话,我们需要生成一个证书文件,这里将使用Java自带的keytool工具来生成jks证书文件,该工具在JDK的bin目录下;

  • 打开CMD命令界面,使用如下命令生成证书文件,设置别名为jwt,文件名为jwt.jks
keytool -genkey -alias jwt -keyalg RSA -keystore jwt.jks
  • 输入密码为123456,然后输入各种信息之后就可以生成证书jwt.jks文件了;

  • 将证书文件jwt.jks复制到项目的resource目录下,然后需要从证书文件中读取RSAKey,这里我们需要在pom.xml中添加一个Spring Security的RSA依赖;
<dependency>    <groupId>org.springframework.securitygroupId>    <artifactId>spring-security-rsaartifactId>    <version>1.0.7.RELEASEversion>dependency>
  • 然后在JwtTokenServiceImpl类中添加方法,从类路径下读取证书文件并转换为RSAKey对象;
/** * Created by macro on 2020/6/22. */@Servicepublic class JwtTokenServiceImpl implements JwtTokenService {    @Override    public RSAKey getDefaultRSAKey() {        //从classpath下获取RSA秘钥对        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "123456".toCharArray());        KeyPair keyPair = keyStoreKeyFactory.getKeyPair("jwt", "123456".toCharArray());        //获取RSA公钥        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();        //获取RSA私钥        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();        return new RSAKey.Builder(publicKey).privateKey(privateKey).build();    }}
  • 我们可以在JwtTokenController中添加一个接口,用于获取证书中的公钥;
/** * JWT令牌管理Controller * Created by macro on 2020/6/22. */@Api(tags = "JwtTokenController", description = "JWT令牌管理")@Controller@RequestMapping("/token")public class JwtTokenController {

    @Autowired    private JwtTokenService jwtTokenService;

    @ApiOperation("获取非对称加密(RSA)算法公钥")    @RequestMapping(value = "/rsa/publicKey", method = RequestMethod.GET)    @ResponseBody    public Object getRSAPublicKey() {        RSAKey key = jwtTokenService.getDefaultRSAKey();        return new JWKSet(key).toJSONObject();    }}
  • 调用该接口,查看公钥信息,公钥是可以公开访问的;

  • JwtTokenServiceImpl中添加根据RSA算法生成和解析JWT令牌的方法,可以发现和上面的HMAC算法操作基本一致;
/** * Created by macro on 2020/6/22. */@Servicepublic class JwtTokenServiceImpl implements JwtTokenService {    @Override    public String generateTokenByRSA(String payloadStr, RSAKey rsaKey) throws JOSEException {        //创建JWS头,设置签名算法和类型        JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.RS256)                .type(JOSEObjectType.JWT)                .build();        //将负载信息封装到Payload中        Payload payload = new Payload(payloadStr);        //创建JWS对象        JWSObject jwsObject = new JWSObject(jwsHeader, payload);        //创建RSA签名器        JWSSigner jwsSigner = new RSASSASigner(rsaKey, true);        //签名        jwsObject.sign(jwsSigner);        return jwsObject.serialize();    }

    @Override    public PayloadDto verifyTokenByRSA(String token, RSAKey rsaKey) throws ParseException, JOSEException {        //从token中解析JWS对象        JWSObject jwsObject = JWSObject.parse(token);        RSAKey publicRsaKey = rsaKey.toPublicJWK();        //使用RSA公钥创建RSA验证器        JWSVerifier jwsVerifier = new RSASSAVerifier(publicRsaKey);        if (!jwsObject.verify(jwsVerifier)) {            throw new JwtInvalidException("token签名不合法!");        }        String payload = jwsObject.getPayload().toString();        PayloadDto payloadDto = JSONUtil.toBean(payload, PayloadDto.class);        if (payloadDto.getExp() new Date().getTime()) {            throw new JwtExpiredException("token已过期!");        }        return payloadDto;    }}
  • JwtTokenController类,添加根据RSA算法生成和解析JWT令牌的接口,使用默认的RSA钥匙对;
/** * JWT令牌管理Controller * Created by macro on 2020/6/22. */@Api(tags = "JwtTokenController", description = "JWT令牌管理")@Controller@RequestMapping("/token")public class JwtTokenController {

    @Autowired    private JwtTokenService jwtTokenService;

    @ApiOperation("使用非对称加密(RSA)算法生成token")    @RequestMapping(value = "/rsa/generate", method = RequestMethod.GET)    @ResponseBody    public CommonResult generateTokenByRSA() {        try {            PayloadDto payloadDto = jwtTokenService.getDefaultPayloadDto();            String token = jwtTokenService.generateTokenByRSA(JSONUtil.toJsonStr(payloadDto),jwtTokenService.getDefaultRSAKey());            return CommonResult.success(token);        } catch (JOSEException e) {            e.printStackTrace();        }        return CommonResult.failed();    }

    @ApiOperation("使用非对称加密(RSA)算法验证token")    @RequestMapping(value = "/rsa/verify", method = RequestMethod.GET)    @ResponseBody    public CommonResult verifyTokenByRSA(String token) {        try {            PayloadDto payloadDto  = jwtTokenService.verifyTokenByRSA(token, jwtTokenService.getDefaultRSAKey());            return CommonResult.success(payloadDto);        } catch (ParseException | JOSEException e) {            e.printStackTrace();        }        return CommonResult.failed();    }}
  • 调用使用RSA算法生成JWT令牌的接口进行测试;

  • 调用使用RSA算法解析JWT令牌的接口进行测试。

参考资料

官方文档:https://connect2id.com/products/nimbus-jose-jwt

项目源码地址

https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-jwt

推荐阅读

  • 线上项目出BUG没法调试?推荐这款阿里开源的诊断神器!
  • Spring Boot 把 Maven 干掉了,正式拥抱 Gradle!
  • 性能优越的轻量级日志收集工具,微软、亚马逊都在用!
  • 15个Github使用技巧,你肯定有不知道的!
  • 写了100多篇原创文章,我常用的在线工具网站推荐给大家!
  • 还在用Swagger生成接口文档?我推荐你试试它.....
  • 你居然还去服务器上捞日志,搭个日志收集系统难道不香么!
  • 真惨!连各大编程语言都摆起地摊了,Java摊位真大!
  • 一个不容错过的Spring Cloud实战项目!
  • 我的Github开源项目,从0到20000 Star!

欢迎关注,点个在看

golang jwt设置过期_听说你的JWT库用起来特别扭,推荐这款贼好用的!相关推荐

  1. redis lua 设置过期_详解 Redis 内存管理机制和实现

    Redis是一个基于内存的键值数据库,其内存管理是非常重要的.本文内存管理的内容包括:过期键的懒性删除和过期删除以及内存溢出控制策略. 最大内存限制 Redis使用 maxmemory 参数限制最大可 ...

  2. 听说你的JWT库用起来特别扭,推荐这款贼好用的!

    以前一直使用的是jjwt这个JWT库,虽然小巧够用, 但对JWT的一些细节封装的不是很好.最近发现了一个更好用的JWT库nimbus-jose-jwt,简单易用,API非常易于理解,对称加密和非对称加 ...

  3. springboot 集成jwt设置过期时间_传说中的jwt,我们来征服一下

    原创:猿逻辑,欢迎分享,转载请保留出处. 本文的完整示例代码,见github仓库.小q只在文中介绍最关键的代码块. https://github.com/yuanluoji/purestart-spr ...

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

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

  5. 蓝湖类似的软件_听说蓝湖收费了?别急,推荐几种类似产品~

    今天一大早准备开始元气满满的工作时 就收到了蓝湖CEO发给我的一封信 WHAT- 以后不能愉快的使用蓝湖了? 群里有各种好友在问替代方案 今天就把我压箱底的好用的平台介绍给大家吧 以下各平台不分先后顺 ...

  6. 安卓编程用什么软件_高等计算、编程计算、化学方程计算!推荐一款非常强大的安卓手机计算器安卓软件...

    大家好,我是元力.这次给大家推荐一款安卓手机使用的超级强大的计算器.这是一个支持多种现实计算器特色功能的科学计算器,日常计算.高等计算.图形计算.编程计算.化学方程计算等等都不在话下.能够应付生活当中 ...

  7. jwt token 过期刷新_不要把 JWT 用作 session

    现在很多人使用 JWT 用作 session 管理,这是个糟糕的做法,下面阐述原因,有不同意见的同学欢迎讨论. 首先说明一下,JWT 有两种: 无状态的 JWT,token 中包含 session 数 ...

  8. jwt判断token是否过期_前端也得搞懂 JWT 这个知识点

    什么是 JWT 概念 JSON Web Token(简称 JWT)是目前最流行的跨域认证解决方案. JWT 原理 JWT 组成 JWT 由三部分组成:Header,Payload,Signature ...

  9. 29.Jwt集成(3):token设置过期时间、异常判断

    29.Jwt集成(3):token设置过期时间.异常判断 参考文章: (1)29.Jwt集成(3):token设置过期时间.异常判断 (2)https://www.cnblogs.com/hualou ...

最新文章

  1. UITabBarItem如何更改高度
  2. 用HTML制作一个漂亮的成绩表,JS-结合html综合练习js的对象——班级成绩表制作...
  3. 宝塔ssl验证域名失败_申请一年期限的AlphaSSL泛域名证书 – 安装第三方证书
  4. 3个月贵了1.6万!特斯拉Model 3今年已涨价6次
  5. Go语言struct{}类型的channel
  6. 俄罗斯方块_代码+解析
  7. zbbz插件使用教程_zbbz加载成功用不了_坐标标注插件zbbz【CAD教学】
  8. thinkpadX1C2021充不进去电(去除静电后依旧无效的来看看)
  9. 盘点那些年火过的php建站系统
  10. quot;紫陀螺quot;网友感触转载系列之…
  11. 神经网络井字棋AI对战版的开发与测试
  12. 基础sql语句的编写,学会这些sql语句的编写一般情况都够用,适合初学者
  13. 爸爸,我们一起把这本书讲给更多人吧!
  14. E4 B8 80 E5 9D 97 E4 BA 92 E5 8A A8 28 E5 8C 97 E4 ... python解码
  15. 高动态环境下基于随机可及集的Path-Guided APF算法的Motion Planning
  16. OpenLooKeng
  17. xgboost解决业务问题实践——司机流失预测模型
  18. 即可app暂停服务?趁现在教你一步一步实现即刻点赞效果
  19. 【编程工具】程序中出现中文乱码的解决方法
  20. 为金融场景而生的数据类型:Numeric

热门文章

  1. CentOS 6.4安装pip,CentOS安装python包管理安装工具pip的方法
  2. mysql 赋给用户权限 grant all privileges on
  3. sqlserver 如何把一列分为一行显示_SqlServer数据库如何快速修改表的一列值
  4. 怎么解决python Non-ASCII character错误
  5. 新浪微博爬虫设计(Python版)
  6. C语言返回文件大小的功能(fseek和ftell的使用)
  7. 两个数组合成一个json对象_两个jsonarray合并
  8. 全国职业院校技能大赛软件测试题目,我院荣获2017年全国职业院校技能大赛软件测试赛项一等奖...
  9. js 取得数组下标_数组的介绍及使用
  10. php分页教程,php 如何分页 教程