JWT简介
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方式,可以在各方之间作为JSON对象安全地传输信息。此信息可以通过数字签名进行验证和信任。JWT可以使用秘密(搭配HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。多用于无状态的身份认证(无状态指服务端不会持久化token).
JWT构造
- token表现形式
xxxxx.yyyyy.zzzzz
分别为Header(头),Payload(有效载荷),Signature(签名)
构造详解
- 第一部分为Header,包含了两个字段,一个表示为采用JWT加密的type字段,二个为token中第三个参数加密的算法(HMAC SHA256,RSA).最终将两个字段构造为json格式经过BASE64Url加密成为密钥的第一部分。
1 | { |
- 已注册的声明(官方已经预定义),包括iss(发行人),exp(到期时间),sub(主题),aud(观众)等.声明的名称不超过三个字符.
- 公开声明,由使用JWT的人随意定义,公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
- 私有声明,由提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
例子:
1
2
3
4
5
6
7
8
9
10{
"iss": "Online JWT Builder",
"iat": 1416797419,
"exp": 1448333419,
"aud": "www.gusibi.com",
"sub": "uid",
"nickname": "goodspeed",
"username": "goodspeed",
"scopes": [ "admin", "user" ]
}部分已注册声明:
1
2
3
4
5
6
7iss: 该JWT的签发者,是否使用是可选的;
sub: 该JWT所面向的用户,是否使用是可选的;
aud: 接收该JWT的一方,是否使用是可选的;
exp(expires): 什么时候过期,这里是一个Unix时间戳,是否使用是可选的;
iat(issued at): 在什么时候签发的(UNIX时间),是否使用是可选的;
nbf (Not Before):如果当前时间在nbf里的时间之前,则Token不被接受;一般都会留一些余地,比如几分钟;,是否使用是可选的;
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
- 第三部分为Signature,创建Signature(签名)部分,必须采用编码Header(标头)编码的Payload(有效负载),secret(秘密,可以是随机生成的盐值或其他加密使用的字符串),Header(标头)中指定的算法,并对其进行签名.如用HMACSHA256加密:
1
2
3
4HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
通过java程序验证token加密方式
1 | package com.tanmibo.study.mystudynotes.JWTtest; |
- 控制台输出结果为
1
2
3
4
5
6
7header BASE64URL加密后:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
payload BASE64URL加密后:eyJleHAiOjE1MzMxOTI3MDIsInVzZXJuYW1lIjoidGFubWIifQ==
sign为前两者加盐值HMAC计算返回原始二进制数据后进行Base64编码:
wwS4uSjq0/HBd+7QFO0EzyEC7IF/4DQszxxYZFpZG4k=
token为:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MzMxOTI3MDIsInVzZXJuYW1lIjoidGFubWIifQ.wwS4uSjq0_HBd-7QFO0EzyEC7IF_4DQszxxYZFpZG4k
!! 其中JWT包中对/ =等字符做过处理
java中的JWT常用的方法.
- 创建token
- HS256方式
1 | try { |
- RS256方式
1 | RSAPublicKey publicKey = //Get the key instance |
- 验证token
- HS256方式
1 | String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; |
- RS256方式
1 | String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; |
- 解码token,并取其中的声明
1 | String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; |
- 解码后,通过方法获取各种参数
- Header
1 | String algorithm = jwt.getAlgorithm(); //获取加密算法 |
私人声明
1 | Claim claim = jwt.getHeaderClaim("owner"); |
- Payload
1 | Issuer ("iss")->发行人 |
私人声明
1 | Map<String, Claim> claims = jwt.getClaims(); |
附:
java-jwt包传送门
我的GitHub同性交友首页tanmibo.github.io