JSON Web Token的使用
通过一段时间的摸索和参考度娘,终于完成了jwt的加密和解密操作,这里不多废话,直接上代码(保证可以运行通过):
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import com.fq.common.util.constants.HttpResultConstant;
import com.fq.common.util.constants.SystemConstant;
import com.fq.common.util.vo.CheckResult;
import com.sun.istack.internal.NotNull;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.TextCodec;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SignatureException;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
/**
* JWT官网:https://jwt.io/introduction/
*/
public class JwtUtil {
//HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)中的secret(即常说的加盐)
public static final String JWT_SECERT = Base64.getEncoder().encodeToString("jwt_secret".getBytes());
//解析token,返回jwt中的部分结构
public static final Integer PARSER_JSON_TYPE_HEADER = 1;//返回header部分
public static final Integer PARSER_JSON_TYPE_PAYLOAD = 2;//返回payload部分
public static final Integer PARSER_JSON_TYPE_SIGNATURE = 3;//返回signature
/**
* 解析JSON Web Token
* @param returnType 返回token中的指定结构
* @param token
* @return 返回的是加密/编码的字符串,header、payload都是可以通过Base64解码,signature是由HMACSHA256算法创建的
*/
public static String parseJWT(Integer returnType, String token) {
String checkResult = "";
if(Objects.isNull(returnType) || null==token || token.trim().equals("")){
return checkResult;
}
try {
//Base64.getDecoder().decode(JWT_SECERT),这是因为这种解析token的方式,
// 如果直接调用Algorithm.HMAC256重构方法传入未解码的JWT_SECERT,
// 会导致内部的JWT_SECERT.getBytes()获取到的字节数组跟调用JwtBuilder.signWith(SignatureAlgorithm.HS256, JWT_SECERT)时(内部会对JWT_SECERT解码并获取字节数组)获取的字节数组不一致,
//从而导致解析失败
Verification require = JWT.require(Algorithm.HMAC256(Base64.getDecoder().decode(JWT_SECERT)));
DecodedJWT decodedJWT = require.build().verify(token);
switch (returnType){
case 1: return decodedJWT.getHeader();
case 2: return decodedJWT.getPayload();
case 3: return decodedJWT.getSignature();
default:break;
}
} catch (Exception e) {
e.printStackTrace();
}
return checkResult;
}
/**
*
* 解析JSON Web Token
* @param jwt
* @return 返回JWT封装对象
* @throws Exception
*/
public static Jwt parseJWT(String jwt){
try {
//解析jwt的简化操作,可以看成是
// JWT.require(Algorithm.HMAC256(Base64.getDecoder().decode(JWT_SECERT))).build().verify(token)的封装操作
return Jwts.parser().setSigningKey(JWT_SECERT).parse(jwt);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
/**
* 生成JWT
* @param payloadMap payload声明参数
* @param sub 面向的对象
* @param expire 有效期(单位ms)
* @return
*/
public static String createJwt(Map<String, Object> payloadMap){
return Jwts.builder()
.setHeader(createJwtHeader())
.addClaims(payloadMap)
.signWith(SignatureAlgorithm.HS256, JWT_SECERT)
.compact();
}
/**
* 创建JSON Web Token header部分
* @return
*/
public static Map<String, Object> createJwtHeader(){
Map<String, Object> map = new HashMap<>();
map.put(JwsHeader.TYPE,JwsHeader.JWT_TYPE);//jwt类型
// map.put(JwsHeader.CONTENT_TYPE,"application/json");//http请求类型
map.put(JwsHeader.ALGORITHM, SignatureAlgorithm.HS256.getValue());//算法名称
return map;
}
/**
* 创建payload(载荷)中的声明部分
* @param sub jwt面向对象
* @param expire 有效时间
* @param params 其他参数,可以是不敏感的用户信息,也可以是payload的中的信息
* @return
*/
public static Map<String, Object> createJwtPayload(String sub, int expire, Map<String, Object> params){
Date issuanceDate = new Date();//签发时间
Date expireDate = DateUtil.getExpireTime(Calendar.SECOND, expire);//有效时间
Map<String, Object> map = new LinkedHashMap<>();
//标准中注册的声明部分(建议但不强制参数)
map.put(Claims.SUBJECT, sub);//jwt所面向的用户
map.put(Claims.ISSUER,"test");//jwt签发者
// 日期转换成秒,
// 否则DecodedJWT jwt = new JWTDecoder(parser, token)导致解析的时候,将毫秒数当做秒来解析,造成日期错误,
// 使得后续解析失败
map.put(Claims.ISSUED_AT, issuanceDate.getTime()/1000);//jwt签发时间,单位s
map.put(Claims.EXPIRATION, expireDate.getTime()/1000);//jwt过期时间,这个过期时间必须要大于签发时间,单位s
// map.put(Claims.NOT_BEFORE, null);//定义在某个时间点之前,该jwt都是不可用的
// map.put(Claims.ID, null);//jwt的唯一身份表示,主要用来作为一次性token,从而回避重放共计
if(Objects.nonNull(params)){
map.putAll(params);
}
return map;
}
public static void main(String[] args) throws Exception {
String encodeJwt = createJwt(createJwtPayload("测试",2, null));
System.out.println(encodeJwt);
// Thread.sleep(3000);
// System.out.println(parseJWT(encodeJwt).toString());
System.out.println(parseJWT(2,encodeJwt).toString());
// System.out.println(new String(java.util.Base64.getDecoder().decode("eyJzdWIiOiLmtYvor5UiLCJpc3MiOiJmYW5ncWkiLCJpYXQiOjE2MDU5MzEyMDIsImV4cCI6MTYwNTkzMTIwNH0")));
}
}