概念
JWT(JSON Web Token)基于在网络应用环境中传递声明的实施JSON的开放标准。
组成
jwt由头部、载荷和签证三部分组成。 然后加密这三部分,然后用.连接在一起 如: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
分别为:header(加密).playload(加密).signature(加密)
1、header
头部,由json组成 具体参数如下:
{
'typ': 'JWT', 'alg': 'HS256' }
- typ:类型
- alg:加密算法
2、playload
负载通常用于存储有效信息json的格式进行存储 有效信息分为三部分:
- 标准中注册的声明;
其中,标准中的注册声明分为以下
iss: jwt签发者; sub: jwt用户; aud: 接收jwt的一方; exp: jwt过期时间必须大于签发时间; nbf: 定义什么时候,什么时候?jwt不可用; iat: jwt签发时间; jwt唯一的身份标志主要用作一次性标志token,避免重放攻击;
- 公开声明;
公共声明可以添加任何信息,通常添加用户的相关信息或其他业务所需的必要信息,但不建议添加敏感信息,因为这部分可以在客户端解密。
- 私人声明;
私人声明是供应商和消费者共同定义的声明,一般不建议存储敏感信息,因为base64是对称解密,这意味着这部分信息可以归类为明文信息。
3、signature
签证由三部分组成:header (base64后的);payload (base64后的);secret (密钥); 所以当我们加解密时,我们需要秘密钥匙,必须保存好
使用
简单使用
1、导入依赖
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency>
2、工具类编写
主要有两种方式,一种是存储自定义类,一种是存储hashMap
自定义类
1、构建类
package com.walker.third.jwt;
import lombok.Data;
/** * 这里的参数可以自己定义,例如我们可以存储用户的id,或者部门id等等 * 之后我们就可以在token进行获取 */
@Data
public class TokenData {
private String name;
private Integer age;
}
2、工具类
package com.walker.third.jwt;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultClaims;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
//jwt标识,这里自己可以进行修改
static String JWT_ID="tokenId";
//秘钥,也可以将其放在配置文件中
static String secretKey="fsfdhufwjnqfjnfafa";
/** * 生成token,claims中存放一个类,方便我们在直接获取类进行处理 */
public static String genToken(TokenData tokenData,Integer expiredMinute){
DateTime date = DateUtil.date();
HashMap<String, Object> claims = new HashMap<>();
claims.put("data", JSONUtil.toJsonStr(tokenData));
//构建JwtBuilder
JwtBuilder builder = Jwts.builder()
.setClaims(claims) //私有声明,用于存放有效信息
.setId(JWT_ID) //是JWT的唯一标识
.setIssuedAt(date) //签发时间
.signWith(SignatureAlgorithm.HS256, secretKey) //加密算法
.setExpiration(DateUtil.offsetMinute(date, expiredMinute));//过期时间
/** * compact:压缩,将header,playload,signature压缩成token字符串 */
String compact = builder.compact();
return compact;
}
/** * 获取tokenData */
public static TokenData getTokenData(String token){
Claims body;
try {
//使用jwt解析器
body = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
return null;
}
//获取到放入的的data
String data = body.get("data", String.class);
//将获取到的json转成对应的类
return JSONObject.parseObject(data,TokenData.class);
}
}
3、测试
@Test
public void genToken2(){
TokenData tokenData = new TokenData();
tokenData.setName("waler");
tokenData.setAge(18);
String token = JwtUtil.genToken(tokenData, 10);
System.out.println(token);
TokenData res = JwtUtil.getTokenData(token);
System.out.println(res);
}
返回结果:
eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoie1wibmFtZVwiOlwid2FsZXJcIixcImFnZVwiOjE4fSIsImV4cCI6MTY1Mzk2OTI2OCwiaWF0IjoxNjUzOTY4NjY4LCJqdGkiOiJ0b2tlbklkIn0.i9ioJYoe8k6X4KlXZu2tU0P0Pfl5D0FH-CApWMf3QOg
TokenData(name=waler, age=18)
HashMap存储
1、工具类方法
package com.walker.third.jwt;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultClaims;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
//jwt标识,这里自己可以进行修改
static String JWT_ID="tokenId";
//秘钥,也可以将其放在配置文件中
static String secretKey="fsfdhufwjnqfjnfafa";
/** * 生成token */
public static String genToken(Map<String,Object> claims,Integer expiredMinute){
DateTime date = DateUtil.date();
JwtBuilder builder = Jwts.builder()
.setClaims(claims) //私有声明,用于存放有效信息
.setId(JWT_ID) //是JWT的唯一标识
.setIssuedAt(date) //签发时间
.signWith(SignatureAlgorithm.HS256, secretKey) //加密算法
.setExpiration(DateUtil.offsetMinute(date, expiredMinute));//过期时间
/** * compact:压缩,将header,playload,signature压缩成token字符串 */
String compact = builder.compact();
return compact;
}
/** * 获取claims */
public static Claims getClaims(String token){
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
} catch (ExpiredJwtException e) {
claims=null;
}
return claims;
}
}
2、测试
@Test
public void genToken(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","walker");
map.put("age",18);
String token = JwtUtil.genToken(map, 10);
System.out.println(token);
Claims claims = JwtUtil.getClaims(token);
System.out.println(claims);
}
返回结果:
eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoid2Fsa2VyIiwiZXhwIjoxNjUzOTcwNzAzLCJpYXQiOjE2NTM5NzAxMDMsImFnZSI6MTgsImp0aSI6InRva2VuSWQifQ.08V-cVMsXxFiJW7l9KhM3968Ke7uKeP7jz3fNRG_Ii0
{
name=walker, exp=1653970703, iat=1653970103, age=18, jti=tokenId}
如果使用的是返回Claims的,会返回对应的过期时间等其他的信息,所以对于返回,还是可以使用Claims,当然也可以自己进行一定的整理
相关知识
JwtBuilder
Header 头部 claims:私有声明 sign 签名
claims,包含两种
JwtBuilder setClaims(Claims var1);
JwtBuilder setClaims(Map<String, Object> var1);
加密算法
一般有下面这里几种,枚举
public enum SignatureAlgorithm {
NONE("none", "No digital signature or MAC performed", "None", (String)null, false),
HS256("HS256", "HMAC using SHA-256", "HMAC", "HmacSHA256", true),
HS384("HS384", "HMAC using SHA-384", "HMAC", "HmacSHA384", true),
HS512("HS512", "HMAC using SHA-512", "HMAC", "HmacSHA512", true),
RS256("RS256", "RSASSA-PKCS-v1_5 using SHA-256", "RSA", "SHA256withRSA", true),
RS384("RS384", "RSASSA-PKCS-v1_5 using SHA-384", "RSA", "SHA384withRSA", true),
RS512("RS512", "RSASSA-PKCS-v1_5 using SHA-512", "RSA", "SHA512withRSA", true),
ES256("ES256", "ECDSA using P-256 and SHA-256", "Elliptic Curve", "SHA256withECDSA", false),
ES384("ES384", "ECDSA using P-384 and SHA-384", "Elliptic Curve", "SHA384withECDSA", false),
ES512("ES512", "ECDSA using P-512 and SHA-512", "Elliptic Curve", "SHA512withECDSA", false),
PS256("PS256", "RSASSA-PSS using SHA-256 and MGF1 with SHA-256", "RSA", "SHA256withRSAandMGF1", false),
PS384("PS384", "RSASSA-PSS using SHA-384 and MGF1 with SHA-384", "RSA", "SHA384withRSAandMGF1", false),
PS512("PS512", "RSASSA-PSS using SHA-512 and MGF1 with SHA-512", "RSA", "SHA512withRSAandMGF1", false);
//..省略其他代码
}
JwtParser jwt解析器
一般用来处理token的解析,能够获取放在playload中的有效信息