JWT(JSON Web Token)是一种用于身份验证和授权的开放标准。它是一种轻量级的、基于JSON的令牌,可以在客户端和服务器之间传递信息。JWT由三部分组成:头部、载荷和签名。头部包含令牌类型和所使用的算法,载荷包含用户信息和其他元数据,签名用于验证令牌的完整性和真实性。JWT的优点包括可扩展性、可靠性和安全性。
简单的说,JWT就是通过数字签名的方式,以JSON对象为载体的开发标准,可以在不同的服务终端之间安全的传输信息。
JWT官网:https://jwt.io/
JSON Web 令牌的紧凑形式由点分隔的三个部分组成,分别是:
因此,JWT 通常如下所示。
xxxxx.yyyyy.zzzzz
Header通常由两部分组成:
令牌的类型(即 JWT)和正在使用的签名算法,例如 HMAC SHA256 或 RSA。
例如:
{
"alg": "HS256",
"typ": "JWT"
}
然后,此JSON被Base64Url编码以形成JWT的第一部分。
令牌的第二部分是有效负载,其中包含声明。声明是有关实体(通常是用户)和其他数据的语句。
示例有效负载可以是:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
然后对有效负载进行 Base64Url 编码以形成 JSON Web 令牌的第二部分。
请注意,对于签名令牌,此信息虽然受到篡改保护,但任何人都可以读取。不要将机密信息放在 JWT 的有效负载或标头元素中,除非它已加密。
要创建签名部分,您必须获取
Header
、Payload
、secret
以及Header
中指定的算法并对其进行签名。签名用于验证消息在此过程中未被更改,并且在使用私钥签名的令牌的情况下,它还可以验证 JWT 的发件人是否是它所说的人。
JWT输出是由点分隔的Header
、Payload
、Signature
的 Base64-URL 字符串,可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(如 SAML)相比更加紧凑。
下面显示了对以前的标头和有效负载进行了编码并使用机密进行签名的 JWT。
==在身份验证中,当用户使用其凭据成功登录时,将返回 JSON Web Token。==由于令牌是凭据,因此必须非常小心以防止安全问题。通常,令牌的保留时间不应超过所需时间。
==每当用户想要访问受保护的路由或资源时,用户都应发送 JWT,通常在使用持有者架构的授权请求头中发送,即Authorization
。==请求头的内容应如下所示:
Authorization: Bearer
说明:JDK8
只需要引入以下依赖就可以
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.9.1version>
dependency>
JDK8
以上的版本需要引入以下已离开
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.9.1version>
dependency>
<dependency>
<groupId>javax.xml.bindgroupId>
<artifactId>jaxb-apiartifactId>
<version>2.3.1version>
dependency>
<dependency>
<groupId>com.sun.xml.bindgroupId>
<artifactId>jaxb-implartifactId>
<version>2.3.3version>
dependency>
<dependency>
<groupId>com.sun.xml.bindgroupId>
<artifactId>jaxb-coreartifactId>
<version>2.3.0version>
dependency>
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
/**
* JWT工具类
*/
public class JwtUtils {
//JWT有效期
public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000 一个小时
//设置签名信息(秘钥明文)
public static final String JWT_KEY = "xha";
/**
* 生成uuid
*
* @return {@link String}
*/
public static String getUUID(){
String token = UUID.randomUUID().toString().replaceAll("-", "");
return token;
}
/**
* 生成jtw,无过期时间,则使用设置的时间
* @param subject token中要存放的数据(json格式)
* @return
*/
public static String createJWT(String subject) {
return getJwtBuilder(subject, JwtUtils.JWT_TTL, getUUID());
}
/**
* 生成jtw,有过期时间。默认为1个小时
* @param subject token中要存放的数据(json格式)
* @param ttlMillis token超时时间
* @return
*/
public static String createJWT(String subject, Long ttlMillis) {
return getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间
}
/**
* 生成jtw,自定义过期时间。
* @param id
* @param subject
* @param ttlMillis
* @return
*/
public static String createJWT(String id, String subject, Long ttlMillis) {
return getJwtBuilder(subject, ttlMillis, id);// 设置过期时间
}
/**
* 创建JWT
*
* @param subject 主题
* @param ttlMillis ttl米尔斯
* @param uuid uuid
* @return {@link String}
*/
private static String getJwtBuilder(String subject, Long ttlMillis, String uuid) {
// 1.根据签名信息生成加密后的秘钥 secretKey
SecretKey secretKey = generalKey();
// 2.获取到当前时间戳
long nowMillis = System.currentTimeMillis();
// 3.签发时间
Date now = new Date(nowMillis);
// 4.JWT的过期时间:当前时间戳+JWT过期时间
long expMillis = nowMillis + ttlMillis;
Date expDate = new Date(expMillis);
return Jwts.builder()
// 1.设置Header信息:令牌的类型和签名算法
.setHeaderParam("typ","JWT")
.setHeaderParam("alg","HS256")
// 2.设置Payload信息,可以是JSON数据
.setSubject(subject)
// 2.1唯一ID
.setId(uuid)
// 2.2签发者
.setIssuer("xha")
// 2.3签发时间
.setIssuedAt(now)
// 2.4设置JWT过期时间
.setExpiration(expDate)
// 3.设置Signature
// 使用HS256对称加密算法签名,第二个参数为秘钥,根据密钥进行加密
.signWith(SignatureAlgorithm.HS256, secretKey)
// 4.对JWT的三部分进行拼接
.compact();
}
/**
* 根据签名信息生成加密后的秘钥 secretKey
* @return
*/
public static SecretKey generalKey() {
// 对签名信息进行Base64Url编码
byte[] encodedKey = Base64.getDecoder().decode(JwtUtils.JWT_KEY);
// SecretKeySpec用于创建加密算法的密钥
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
/**
* 解析JWT
*
* @param jwt
* @return
* @throws Exception
*/
public static Claims parseJWT(String jwt) throws Exception {
// 根据签名信息生成加密后的秘钥 secretKey
SecretKey secretKey = generalKey();
return Jwts.parser()
// 根据密钥进行解密
.setSigningKey(secretKey)
// JWT对象
.parseClaimsJws(jwt)
.getBody();
}
}
public class TestJWT {
public static void main(String[] args) {
String userId = "123456";
String jwt = JwtUtils.createJWT(userId);
System.out.println(jwt);
}
}
控制台输出JWT
使用JWT官网的JWT解析工具进行解析JSON Web Tokens - jwt.io
解析JWT
public static void main(String[] args) {
String userId = "123456";
String jwt = JwtUtils.createJWT(userId);
System.out.println(jwt);
try {
Claims claims = JwtUtils.parseJWT(jwt);
System.out.println(claims);
} catch (Exception e) {
throw new RuntimeException(e);
}
}