【JWT】jwt令牌研究

简介: JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简介的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公钥/私钥对来签名,防止被篡改。

📫 作者简介:No8g攻城狮,热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长,专注于研究 Java/Spring/SpringBoot/大数据/计算机底层原理/源码,就职于大型物联网公司后端高级工程师,擅长物联网领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。📫  

🏆 CSDN认证博客专家博主/后端领域优质创作者/内容合伙人、阿里云/华为云/签约博主、InfoQ/掘金社区/OSCHINA签约作者,全网7万多粉丝支持! 🏆  

🔥 如果此文还不错的话,还请👍点赞、关注、收藏三连支持👍一下博主~ 十分感谢,发布的博客会不定期送书的福利哈~ 🔥


一、JWT介绍

在介绍JWT之前先看一下**传统校验令牌**的方法,如下图:

1.png

- 问题:

传统授权方法的问题是用户每次请求资源服务,资源服务都需要携带令牌访问认证服务去校验令牌的合法性,并根据令牌获取用户的相关信息,性能低下。为什么会说性能低下呢? 原因就是用户(客户端)请求资源服务,资源服务都需要携带令牌访问认证服务去校验令牌的合法性,要明确一来一回的请求和响应都是需要消耗时间的哦。

- 解决方法:

使用JWT的思路是,用户认证通过后 会得到一个JWT令牌,JWT令牌中已经包括了用户相关的信息,客户端只需要携带JWT访问资源服务,资源服务根据事先约定的算法自行完成令牌校验(这就是比较厉害的哦),无需每次都请求认证服务完成授权(耗时短)。

JWT令牌授权过程如下图:


2.png

说半天了,还不知道什么是JWT令牌吧,请听老夫细细道来:

1.1 JWT概念

什么是JWT?

JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简介的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公钥/私钥对来签名,防止被篡改。

英语比较好的同学,可以去官网看看哦(前提你必须能看老外的网站)。

官网:https://jwt.io/

标准:https://tools.ietf.org/html/rfc7519

我给你贴个图,慢慢看吧

3.png

1.2 JWT优缺点

JWT令牌的优点:

1. jwt基于json,非常方便解析。

2. 可以在令牌中自定义丰富的内容,易扩展。

3. 通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。

4. 资源服务使用JWT可不依赖认证服务即可完成授权。

缺点:

- JWT令牌较长,占存储空间比较大。

二、令牌结构

通过学习JWT令牌结构为自定义jwt令牌打好基础。

JWT令牌由三部分组成(Header,Payload,Signature),每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz

2.1 Header

第二部分是头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA)

一个例子如下:

下边是Header部分的内容

```json

{

 "alg": "HS256",

 "typ": "JWT"

}

```

将上边的内容使用Base64Url编码,得到一个字符串就是JWT令牌的第一部分。

2.2 Payload

第二部分是负载,内容也是一个json对象,它是存放有效信息的地方,它可以存放jwt提供的现成字段,比如:iss(签发者),exp(过期时间戳), sub(面向的用户)等,也可自定义字段。

此部分不建议存放敏感信息,因为此部分可以解码还原原始内容。

最后将第二部分负载使用Base64Url编码,得到一个字符串就是JWT令牌的第二部分。

一个例子:

```json

{

 "sub": "1234567890",

 "name": "456",

 "admin": true

}

```

2.3 Signature

第三部分是签名,此部分用于防止jwt内容被篡改。

这个部分使用base64url将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用header中声明签名算法进行签名。

一个例子:

```js

 

HMACSHA256(

 base64UrlEncode(header) + "." +

 base64UrlEncode(payload),

 secret)

```

base64UrlEncode(header):jwt令牌的第一部分。

base64UrlEncode(payload):jwt令牌的第二部分。

secret:签名所使用的密钥。

三、JWT入门

Spring Security 提供对JWT的支持,本文我们使用Spring Security 提供的JwtHelper来创建JWT令牌,校验JWT令牌等操作。

生成私钥和公钥

JWT令牌生成采用非对称加密算法

3.1 生成密钥证书

下边命令生成密钥证书,采用RSA 算法每个证书包含公钥和私钥

`keytool -genkeypair -alias jykey -keyalg RSA -keypass jiaoyu -keystore jy.keystore -storepass jiaoyukeystore`

Keytool 是一个java提供的证书管理工具

-alias:密钥的别名

-keyalg:使用的hash算法

-keypass:密钥的访问密码

-keystore:密钥库文件名,jy.keystore保存了生成的证书

-storepass:密钥库的访问密码

查询证书信息:

`keytool -list -keystore jy.keystore `

删除别名

`keytool -delete -alias jykey -keystore jy.keystore`

3.2 导出公钥

openssl是一个加解密工具包,这里使用openssl来导出公钥信息。

安装 openssl:http://slproweb.com/products/Win32OpenSSL.html

我的安装资料为 `Win64OpenSSL-1_1_0g.exe`

配置openssl的path环境变量(可以参考哦),本教程配置在D:\OpenSSL-Win64\bin

cmd进入jy.keystore文件所在目录执行如下命令:

`bash

keytool -list -rfc --keystore jy.keystore | openssl x509 -inform pem -pubkey`

输入密钥库密码:

![4.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dd3e9c03bc4f428da2f7b68f5cff8296~tplv-k3u1fbpfcp-watermark.image?)

下边这一段就是公钥内容:

-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAijyxMdq4S6L1Af1rtB8SjCZHNgsQG8JTfGy55eYvzG0B/E4AudR2prSRBvF7NYPL47scRCNPgLnvbQczBHbBug6uOr78qnWsYxHlW6Aa5dI5NsmOD4DLtSw8eX0hFyK5Fj6ScYOSFBz9cd1nNTvx2+oIv0lJDcpQdQhsfgsEr1ntvWterZt/8r7xNN83gHYuZ6TM5MYvjQNBc5qC7Krs9wM7UoQuL+s0X6RlOib7/mcLn/lFLsLDdYQAZkSDx/6+t+1oHdMarChIPYT1sx9Dwj2j2mvFNDTKKKKAq0cv14Vrhz67Vjmz2yMJePDqUi0JYS2r0iIo7n8vN7s83v5uOQIDAQAB-----END PUBLIC KEY-----

将上边的公钥拷贝到文本文件中,合并为一行。

四、生成jwt令牌

在认证工程创建测试类,测试jwt令牌的生成与验证。

```java

 

//生成一个jwt令牌

@Test

public void testCreateJwt(){

   //证书文件

   String key_location = "jy.keystore";

   //密钥库密码

   String keystore_password = "jiaoyukeystore";

   //访问证书路径

   ClassPathResource resource = new ClassPathResource(key_location);

   //密钥工厂

   KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, keystore_password.toCharArray());

   //密钥的密码,此密码和别名要匹配

   String keypassword = "jiaoyu";

   //密钥别名

   String alias = "jykey";

   //密钥对(密钥和公钥)

   KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias,keypassword.toCharArray());

   //私钥

   RSAPrivateKey aPrivate = (RSAPrivateKey) keyPair.getPrivate();

   //定义payload信息

   Map<String, Object> tokenMap = new HashMap<>();

   tokenMap.put("id", "123");

   tokenMap.put("name", "mrt");

   tokenMap.put("roles", "r01,r02");

   tokenMap.put("ext", "1");

   //生成jwt令牌

   Jwt jwt = JwtHelper.encode(JSON.toJSONString(tokenMap), new RsaSigner(aPrivate));

   //取出jwt令牌

   String token = jwt.getEncoded();

   System.out.println("token="+token);

}

```

五、验证jwt令牌

```java

 

//资源服务使用公钥验证jwt的合法性,并对jwt解码

   @Test

   public void testVerify(){

       //jwt令牌

       String token ="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHQiOiIxIiwicm9sZXMiOiJyMDEscjAyIiwibmFtZSI6Im1ydCIsImlkIjoiMTIzIn0.KK7_67N5d1Dthd1PgDHMsbi0UlmjGRcm_XJUUwseJ2eZyJJWoPP2IcEZgAU3tUaaKEHUf9wSRwaDgwhrwfyIcSHbs8oy3zOQEL8j5AOjzBBs7vnRmB7DbSaQD7eJiQVJOXO1QpdmEFgjhc_IBCVTJCVWgZw60IEW1_Lg5tqaLvCiIl26K48pJB5f-le2zgYMzqR1L2LyTFkq39rG57VOqqSCi3dapsZQd4ctq95SJCXgGdrUDWtD52rp5o6_0uq-mrbRdRxkrQfsa1j8C5IW2-T4eUmiN3f9wF9JxUK1__XC1OQkOn-ZTBCdqwWIygDFbU7sf6KzfHJTm5vfjp6NIA";

       //公钥

       String publickey = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAijyxMdq4S6L1Af1rtB8SjCZHNgsQG8JTfGy55eYvzG0B/E4AudR2prSRBvF7NYPL47scRCNPgLnvbQczBHbBug6uOr78qnWsYxHlW6Aa5dI5NsmOD4DLtSw8eX0hFyK5Fj6ScYOSFBz9cd1nNTvx2+oIv0lJDcpQdQhsfgsEr1ntvWterZt/8r7xNN83gHYuZ6TM5MYvjQNBc5qC7Krs9wM7UoQuL+s0X6RlOib7/mcLn/lFLsLDdYQAZkSDx/6+t+1oHdMarChIPYT1sx9Dwj2j2mvFNDTKKKKAq0cv14Vrhz67Vjmz2yMJePDqUi0JYS2r0iIo7n8vN7s83v5uOQIDAQAB-----END PUBLIC KEY-----";

       //校验jwt

       Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(publickey));

       //获取jwt原始内容

       String claims = jwt.getClaims();

       //jwt令牌

       String encoded = jwt.getEncoded();

       System.out.println(encoded);

   }

```

到这里本文就告一段落了,如果的新的内容将会随时更新的,尽请关注。

如果感觉写的好,确实帮助了你,那就麻烦帮忙点个赞,多谢!


**本文首发于CSDN,为博主原创文章,如果需要转载,请注明出处,谢谢!**

完结!

相关文章
|
3月前
|
存储 JSON 安全
JWT令牌详解
JWT令牌详解
|
21天前
|
JSON Java API
【Azure Developer】如何验证 Azure AD的JWT Token (JSON Web 令牌)?
【Azure Developer】如何验证 Azure AD的JWT Token (JSON Web 令牌)?
|
4月前
|
JSON 安全 程序员
[JavaWeb]——JWT令牌技术,如何从获取JWT令牌
[JavaWeb]——JWT令牌技术,如何从获取JWT令牌
JWT令牌,JWT令牌的后续使用,在其他端口中使用的注意事项?如果你编写了JWT令牌的话,在下一次请求当中,都需要添加的,如果你已经配置好了WebConfig和Inter 就不用配了,添加了拦截器之后
JWT令牌,JWT令牌的后续使用,在其他端口中使用的注意事项?如果你编写了JWT令牌的话,在下一次请求当中,都需要添加的,如果你已经配置好了WebConfig和Inter 就不用配了,添加了拦截器之后
|
3月前
|
JSON 前端开发 数据格式
关于JWT令牌和过滤器以及拦截器的实现流程
JWT令牌用于验证用户请求合法性,登录时通过Filter或Interceptor校验账号密码,生成JWT并返回给前端保存。请求时,后端通过解析令牌检查其完整性、时效性和合法性。Filter在请求处理前检查是否携带JWT,Interceptor的preHandle方法同样用于此目的。两者选择其一即可,拦截器配置更精确但稍复杂。
|
4月前
|
存储 JSON 算法
SpringBoot之JWT令牌校验
SpringBoot之JWT令牌校验
137 2
|
4月前
|
JSON 前端开发 Java
|
4月前
|
JSON 前端开发 Java
JWT解密:探秘令牌魔法与Java的完美交互
JWT解密:探秘令牌魔法与Java的完美交互
53 0
JWT解密:探秘令牌魔法与Java的完美交互
|
4月前
|
前端开发 Java Spring
SpringBoot通过拦截器和JWT令牌实现登录验证
该文介绍了JWT工具类、匿名访问注解、JWT验证拦截器的实现以及拦截器注册。使用`java-jwt`库生成和验证JWT,JwtUtil类包含generateToken和verifyToken方法。自定义注解`@AllowAnon`允许接口匿名访问。JwtInterceptor在Spring MVC中拦截请求,检查JWT令牌有效性。InterceptorConfig配置拦截器,注册并设定拦截与排除规则。UserController示例展示了注册、登录(允许匿名)和需要验证的用户详情接口。
675 1
|
4月前
|
前端开发 数据安全/隐私保护
JWT令牌
JWT令牌
40 0