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

以前一直使用的是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.
 */
@Service
public 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)
@Builder
public 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.
 */
@Service
public 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令牌的接口进行测试;
75cfde3202464ade3542e2f5ceb57072.png
  • 调用使用HMAC算法解析JWT令牌的接口进行测试。
77b4187aa4b43ba441f6f75f271abf13.png

非对称加密(RSA)

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

  • 如果我们需要使用固定的公钥和私钥来进行签名和验证的话,我们需要生成一个证书文件,这里将使用Java自带的keytool工具来生成jks证书文件,该工具在JDK的bin目录下;
c68582920ee3c86ab927fe0bd7131dc3.png
  • 打开CMD命令界面,使用如下命令生成证书文件,设置别名为jwt,文件名为jwt.jks
keytool -genkey -alias jwt -keyalg RSA -keystore jwt.jks
  • 输入密码为123456,然后输入各种信息之后就可以生成证书jwt.jks文件了;
0daac147b5d0e2486a2d1ff31bf24f13.png
  • 将证书文件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.
 */
@Service
public 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();
    }
}
  • 调用该接口,查看公钥信息,公钥是可以公开访问的;
7918e58dcd62ee21f90e09eb7ac45a79.png
  • JwtTokenServiceImpl中添加根据RSA算法生成和解析JWT令牌的方法,可以发现和上面的HMAC算法操作基本一致;
/**
 * Created by macro on 2020/6/22.
 */
@Service
public 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令牌的接口进行测试;
8135aa5e05f6ee233182f70f614b0e0b.png
  • 调用使用RSA算法解析JWT令牌的接口进行测试。
54a0af5258c852c7c179ad5b6ef07030.png

参考资料

官方文档: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!

a6a1b1ea48d96456bd80003228fb3f3b.png

欢迎关注,点个在看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367322.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

随机验证码 pillow

安装 pip3 install pillow 基本使用 import PILfrom PIL import Imagefrom PIL import ImageDraw, ImageFontimport random 1.创建图片 from PIL import Image img Img.new(mode"RGB",size(120.30),color(255,255,255))# 在图片查看器中打开 # img.show()# 保存在本地…

微信小程序裁剪图片成圆形

前言 最近在开发小程序&#xff0c;产品经理提了一个需求&#xff0c;要求微信小程序换头像&#xff0c;用户剪裁图片必须是圆形&#xff0c;也在github上看了一些例子&#xff0c;一般剪裁图片用的都是方形&#xff0c;所以自己打算写一个小组件&#xff0c;可以把图片剪裁成圆…

MFC控件编程之组合框跟列表框

MFC控件编程之组合框跟列表框 一丶简介 如果要使用组合框跟列表框.那么就要知道.组合框列表框是最核心的东西就是索引. 索引是从0开始的. 二丶组合框列表框常用的方法 AddString(字符串) 添加一个字符串.放到最后面. DeleteString(索引); 删除指定索引的字符串. int GetCurSe…

多重继承_Python 和 Java 基础对比 10 —— 类的封装、继承和多态

Python大星一、Python 类的封装、继承和多态封装继承Python 支持多父类的继承机制&#xff0c;所以需要注意圆括号中基类的顺序&#xff0c;若是基类中有相同的方法名&#xff0c;并且在子类使用时未指定&#xff0c;Python 会从左至右搜索基类中是否包含该方法。一旦查找到则直…

前端也要会的数据结构 (不定期更新篇)

前端的软肋 一说到前端大家脑子里只有&#xff0c;布局、展示数据、修改样式等等。可是数据是哪里来的呢&#xff1f;后端给的后端给的。数据的结构呢&#xff1f;后端给啥用啥。 这就是前端的一个软肋。我们的业务让我们并不需要过深入的了解数据结构&#xff0c;数据结构和…

鸿蒙系统8月9日发布,8月9日,华为发布EMUI10.0系统+展示鸿蒙系统

8月9日&#xff0c;华为将召开华为全球开发者大会&#xff0c;本次大会邀请了5000名全球开发者、1500位合作伙伴&#xff0c;是华为历来规模最大的一次会议。在华为开发者大会上&#xff0c;华为将推出EMUI 10.0系统&#xff0c;由华为消费也业务软件总裁王成录主讲。EMUI是手机…

matlab main函数_Python 和MATLAB 制作Gif 图像

主要内容概述&#xff1a;预备知识MATLAB 代码实现GIF使用imageio 生成GIF使用animation 交互式方式生成GIF总结0&#xff0c;预备知识首先了解下什么是GIF 图片&#xff0c;以及常用的图片格式。GIF的全称是Graphics Interchange Format&#xff0c;可译为图形交换格式&#x…

ORB-SLAM2的特征提取算法

ORB-SLAM2跟踪线程对相机输入的每一帧图像进行跟踪处理&#xff0c;如下图所示&#xff0c;主要包括4步&#xff0c;提取ORB特征、从上一帧或者重定位来估计初始位姿、局部地图跟踪和关键帧处理。 以下结合相关理论知识&#xff0c;阅读ORB-SLAM2源代码&#xff0c;从而理解ORB…

引导界面图标好大_游戏里那些图标和界面,原来是这么设计出来的?

UI设计最硬核的思维 就是功能微信现在在做一种全面连接的功能&#xff0c;而游戏需要实现的是人机互动的功能。实现并完善功能&#xff0c;是互联网、游戏、网站、渴望UI人才的根本原因。如果说有电脑的世界是一片很大的面&#xff0c;那么可视化的操作&#xff0c;都是UI设计师…

爬格子呀9.17(图论)

刘汝佳的紫书差不多就告一段落吧&#xff0c;我觉得可以了&#xff0c;怎么说呢&#xff0c;这书也陪着自己走了一年多了吧&#xff0c;也目睹了从一个啥也不会的萌新到一个稍微会一点的萌新的转变。 差不多开始下本书吧&#xff0c;自己也大三了&#xff0c;时间真的有点紧啊w…

一个vue加egg.js的博客

之前自己的博客是用hexo做的&#xff0c;后面想做一个有后台的博客就打算用vue加node来试试&#xff0c;于是就有了这个博客。 项目地址 W-Blog W-Blog是一个基于vue和node的小小小博客 前端用vue&#xff0c;后端用egg.js 快速入门 技术栈 前端&#xff1a; 用户端&#…

android音量图标不见了,电脑声音图标不见了如何解决?

最近有电脑用户反映&#xff0c;看视频时觉得声音太小了&#xff0c;要调大点声&#xff0c;却发现任务栏上的声音图标不见了&#xff0c;想调个声音都难。那么&#xff0c;电脑声音图标不见了如何解决呢?我们一起往下看看。方法步骤一、XP系统下找回任务栏上的声音图标1、重启…

认识iOS系统架构

关于本文&#xff1a; 文章主要介绍iOS系统架构中的四层结构的内容、常用的框架、大致的功能&#xff0c;然后对iOS开发人员的发展提出自己的一些拙见。 一、iOS系统是基于UNIX系统&#xff0c;所有从系统稳定性上来说的确比其他操作系统的产品要好。 iOS在系统架构上分为4层&a…

Java泛型教程–示例类,接口,方法,通配符等

泛型是Java编程的核心功能之一&#xff0c;它是Java 5中引入的。如果您使用的是Java Collections &#xff0c;并且版本5或更高版本&#xff0c;则可以肯定使用了它。 在集合类中使用泛型非常容易&#xff0c;但是它提供了比仅创建集合类型更多的功能&#xff0c;我们将在本文中…

html5中音乐播放器怎么写,打造属于自己的音乐播放器 HTML5之audio标签

我的音乐播放器HTML5中增加了Audio和Video标签&#xff0c;这两个标签的用法非常相似。功能却是相当强大&#xff0c;我们先来看一下Audio标签各个浏览器的支持情况。这里用的依然是Can I Use这个在线网站&#xff0c;相信学习前端的同学应该都不陌生。Can I Use我们可以看到&a…

初识react(四) react中异步解决方案之 redux-saga

回顾 初识react(一) 揭开jsx语法和虚拟DOM面纱初识react(二) 实现一个简版的html redux.js的demo初识react(三)在 react中使用redux来实现简版计数器初识react(四) react中异步解决方案之 redux-saga初识react(五) 数据流终极解决方案 dva(零配置) 今天demo是实现一个异步的计…

C# WinFrom 关于MDI

dev是一个牛B 到没边的控件 我们正常用winform做个原始mdi窗体 一点都不好看 但 用的dev只需要一个控件 就可让显示舒服多了 建一个项目 上边放一个 xtraTabbedMdiManager1 一个button1 button1.click如下&#xff1a; Form frm new Form(); frm.MdiParent this; frm.Text &…

Jfinal 文件上传

JFinal上传文件 uploadify 可以在http://www.uploadify.com/ 下载。 在原项目的基础上。 uploadify使用&#xff1a; <input id"file_upload_1" name"file_upload" type"file" multiple"true"> /** param uploader 文件上传方法…

轻量级的开源集成:Apache Camel还是Spring集成?

首先&#xff0c;为全面披露信息&#xff0c;在过去的1.5年中&#xff0c; 我一直担任 FuseSource&#xff08;现为Red Hat&#xff09; 的顾问&#xff0c;为零售&#xff0c;运输&#xff0c;银行/金融等不同行业的大型和小型公司提供SOA和集成项目支持。我的专长是使用该领域…

WePY:在质疑中前进 | 文末福利

WePY 作者介绍 Q: 先介绍一下自己吧~ Gcaufy: 我 2011 年大学毕业之后&#xff0c;阴错阳差的走上了 Web 开发的道路。15 年之前算是自由职业 SOHO 工作&#xff0c;主要给一些国外的大公司做外包系统&#xff0c;更多的是做后端开发。15 年之后以前端工程师的身份加入腾讯&a…