什么是 JSON Web Token(JWT)?
JSON Web 令牌 (JWT) 是一种开放标准 (RFC 7519),它定义了一种紧凑且独立的方式,用于在各方之间以 JSON 对象的形式安全地传输信息。此信息可以验证和信任,因为它是经过数字签名的。JWT 可以使用密钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
尽管 JWT 可以加密以提供各方之间的保密性,但我们将专注于签名令牌。签名令牌可以验证其中包含的声明的完整性,而加密令牌则向其他方隐藏这些声明。当使用公钥/私钥对对令牌进行签名时,签名还证明只有持有私钥的一方才是签名的一方。
(以上摘自JWT官网(https://jwt.io/introduction))
JWT本质上就是一个字符串
JWT的构成
jwt由header(头),payload(负载),sign(签名)三部分组成,中间用圆点(.)分隔。
header通常由两部分组成:令牌的类型(即 JWT)和正在使用的签名算法,例如 HMAC SHA256 或 RSA。
例如:
{
"alg": "HS256",
"typ": "JWT"
}
第二部分是payload,其中包含声明。声明是有关实体(通常是用户)和其他数据的语句。 有三种类型的声明:已注册、公共和私人声明。
标准中注册的声明 (建议但不强制使用) :
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
例如:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
第三部分是sign,将header,payload分别base64Url编码,再加上秘钥(盐值),三部分用header中指定的算法计算后就是jwt,例如:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
尝试手写一个JWT
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.Date;
public static String MyCreateJWT(){
String jwtSecret="NB666";//秘钥或者叫盐值
//header
JSONObject header = new JSONObject();
header.put("alg","HS256");
header.put("typ","JWT");
//payload
Date date = new Date();
JSONObject payload = new JSONObject();
payload.put("iat",date);//iat表示创建时间
payload.put("exp",date.getTime()+1000*60*60*2);//exp表示过期时间,此处两小时后过期
//base64编码header,payload
String base64Header = Base64.getEncoder().encodeToString(header.toJSONString().getBytes());
String base64Payload = Base64.getEncoder().encodeToString(payload.toJSONString().getBytes());//真正的jwt实际上使用的base64url编码,这里用base64
//使用MD5生成sign
String sign = DigestUtils.md5Hex(base64Header + base64Payload + jwtSecret);//加盐是最关键的,否则jwt没有任何意义
String jwt=base64Header+"."+base64Payload+"."+sign;//最终创建的jwt
return jwt;
}
能手写出一个jwt后,再去反向解密(验证)jwt也就比较容易了