目录
一、JWT是什么?
在当今的Web开发中,安全认证和授权变得尤为重要。JWT(JSON Web Tokens)是一种开放标准(RFC 7519),它定义了一种简洁、紧凑且自包含的方式,用于在各方之间安全地传输信息。但这种传输并不是保密的传输,只是验证真伪的传输,信息是可以被看见的,只是做不了假.这种信息可以被验证和信任.
JWT全称:JSON Web Token (官网:JSON Web Tokens - jwt.ioJSON Web Tokens - jwt.ioJSON Web Tokens - jwt.io)
简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。
紧凑:指的是它能够以较小的体积包含所有的信息。JWT使用Base64Url编码算法JWT支持多种加密算法,如HS256、RS256等,这些算法能够在保证安全性的同时,保持令牌的大小不会过大。
自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。JWT包含了所有必要的信息来验证其有效性,不需要额外的查询或数据库操作。如:可以直接在jwt令牌中存储用户的相关信息。
简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。
用世俗的说法就是:token就像身份证的号码,号码是都可见的,里面每个字母都蕴含信息,虽然大家都知道号码,但是你不能作假.然后你使用身份证开房之类的就相当于客户端去访问服务器,酒店的前台检验的你身份证真假,服务器就是检查客户端的token的真假.
二、JWT的组成
JWT由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)用.分隔。这三部分以.
分隔,形如xxxxx.yyyyy.zzzzz
。
假设我们有一个JWT如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
头部(Header):包含了令牌的类型和所使用的加密算法。
- 编码后:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
- 解码后:
{ "alg": "HS256", "typ": "JWT" }
头部告诉我们签名算法(HS256)和令牌类型(JWT)
载荷(Payload):存放实际的数据,可以是任何形式的JSON对象。编码后:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
解码后:{ "name": "John Doe", "admin": true, "roles": ["user", "admin"], "exp": 1687016741 }
载荷包含了声明信息,如用户姓名、是否为管理员、用户角色和过期时间。
签名(Signature):用于验证令牌的发送者和内容是否被篡改。签名由头部、载荷、秘钥和指定的算法生成。
-
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c签名是对头部和载荷的加密,确保令牌的完整性和可靠性。
在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号。需要注意的是Base64是编码方式,而不是加密方式。
三、JWT应用场景
WT令牌最典型的应用场景就是登录认证:
1.客户端请求认证:用户通过用户名和密码请求登录。
2.服务器验证请求:服务器验证用户凭证,如果有效,生成JWT。
3.客户端存储令牌:客户端接收到JWT后,存储在本地(通常是LocalStorage或SessionStorage)。
4.客户端发送令牌:之后的每个请求都带有这个JWT,通常放在HTTP头的Authorization字段中。
5.服务器验证令牌:服务器验证JWT的有效性,如果有效则处理请求,否则拒绝。
四、生成和校验JWT令牌
要想使用JWT令牌,需要先引入JWT的依赖:
<!-- JWT依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
在引入完JWT来赖后,就可以调用工具包中提供的API来完成JWT令牌的生成和校验。
生成JWT代码实现:
@Test
public void genJwt(){
Map<String,Object> claims = new HashMap<>();
claims.put("id",1);
claims.put("username","Tom");
String jwt = Jwts.builder()
.setClaims(claims) //自定义内容(载荷)
.signWith(SignatureAlgorithm.HS256, "itheima") //签名算法
.setExpiration(new Date(System.currentTimeMillis() + 24*3600*1000)) //有效期一天
.compact();//将JWT转换为一个紧凑的字符串形式
System.out.println(jwt);
}
运行测试方法,输出的结果就是生成的JWT令牌,,通过英文的点分割对三个部分进行分割,我们可以将生成的令牌复制一下,然后打开JWT的官网,将生成的令牌直接放在Encoded位置,此时就会自动的将令牌解析出来。
前两个部分是base64编码,所以是可以直接解码出来。但最后一个部分并不是base64编码,是经过签名算法计算出来的,所以最后一个部分是不会解析的。
实现了JWT令牌的生成,下面我们接着使用Java代码来校验JWT令牌(解析生成的令牌) ,这个部分也是鉴别这个令牌真伪的地方,前面都是token令牌的载荷和说明:
public class JWT { @Test public void test(){ SecretKey secretKey = Keys.secretKeyFor(signatureAlgorithm.Hs256);//(生成2次密钥) 这个是jwt给的生成密钥的官方方法. // 但是这个密钥生成出来的时候已经被加密过了.已经被decode过了.这里我称为2次密钥,好理解.但是我们想验证token是需要用1次密钥才可以验证真假的. // 但是jwt给的方法是直接创建2次密钥的,所以我们得解密拿到1次密钥.也就是str String str = Encoders.BASE64.encode(secretKey.getEncoded()); System.out.println(str);//这是1次密钥 String Str ="Le++08NOWVXWo3+SJtAtnjBW9iA00VPL@c0mMrol2fU=";//1次密钥 我们想要验证token是否是真的,需要将1次密钥放入检验的地方,就可以辨别真假. Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(Str));//2次密钥 Map<String,Object> claim =new HashMap<>();claim.put("id",1);claim.put("name","zhangsan"); String token = Jwts.builder().setClaims(claim).setExpiration(new Date(System.currentTimeMillis()+60*60*1000)) .signWith(key).compact();//builder是构建令牌,setclaims是将加入载荷,Expiration是设置时间,signwith是密钥.compact是组合起来将这些 System.out.println(token);//打印token } }
5.实战使用
生成令牌
这里直接拿之前生成好的1次密钥使用了
解析令牌
JWT虽然提供了一种简洁、安全的认证方式,但也有一些注意事项,如令牌的有效期设置、敏感信息的存储等。在使用JWT时,应结合具体的应用场景和需求进行合理的设计和配置。总之,JWT是现代Web应用中一个非常有用的工具,它简化了认证流程,提高了应用的安全性和可扩展性。通过理解其原理和正确的使用方法,你可以有效地保护你的应用和用户数据。