package com.zqf.shiro.utils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.zqf.shiro.pojo.LoginUser;
import io.jsonwebtoken.*;
import org.apache.commons.beanutils.BeanMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.Key;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author Hero
* @date 7/12/2017
*/
public class JwtHelper {
private static final Logger log = LoggerFactory.getLogger(JwtHelper.class);
public static boolean veritySigned(String jsonWebToken, String base64Security) {
return Jwts.parser()
.setSigningKey(Base64.getDecoder().decode(base64Security))
.isSigned(jsonWebToken);
}
public static boolean verify(String jsonWebToken, String base64Security) {
try {
final Claims claims = (Claims) Jwts.parser()
.setSigningKey(base64Security)
.parse(jsonWebToken)
.getBody();
return true;
} catch (ExpiredJwtException e) {
log.debug("token过期失效");
return false;
} catch (MalformedJwtException e) {
log.debug("未知错误");
return false;
} catch (SignatureException e) {
log.debug("token签名失效");
return false;
} catch (IllegalArgumentException e) {
log.debug("非法参数");
return false;
}
}
public static String createAccessToken(LoginUser user, String iss, String aud, long ttlMillis, String base64Security) {
// 采用椭圆曲线加密算法, 提升加密速度
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//生成签名密钥
SignatureAlgorithm signatureAlgorithm = getAlgorithm();
Key signingKey = getKey(base64Security, signatureAlgorithm.getJcaName());
Map<String, Object> claims = user2map(user);
//添加构成JWT的参数
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
.addClaims(claims)
.setIssuer(iss)
.setAudience(aud)
.setSubject(user.getUsername())
.signWith(signatureAlgorithm, signingKey);
//添加Token过期时间
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp).setNotBefore(now);
}
//生成JWT
return builder.compact();
}
public static String createRefreshToken(String userName, String iss, String aud, long ttlMillis, String base64Security) {
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//生成签名密钥
SignatureAlgorithm signatureAlgorithm = getAlgorithm();
Key signingKey = getKey(base64Security, signatureAlgorithm.getJcaName());
//添加构成JWT的参数
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
.claim("scope", "REFRESH")
.setIssuer(iss)
.setAudience(aud)
.setSubject(userName)
.signWith(signatureAlgorithm, signingKey);
//添加Token过期时间
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp).setNotBefore(now);
}
//生成JWT
return builder.compact();
}
/**
* 获取jwt 唯一身份识别码
*
* @return 登录用户信息
*/
public static String createJti() {
return String.valueOf(System.nanoTime());
}
public static LoginUser verifyAndGetUser(String jwt, String base64Security) {
if (StringUtils.isBlank(jwt)) {
log.debug("JWT校验commons:jwt为空,校验失败");
throw new IllegalArgumentException("jwt 不能为空");
}
if (StringUtils.isBlank(base64Security)) {
log.debug("JWT校验commons:base64Security为空,校验失败");
throw new IllegalArgumentException("key 不能为空");
}
if (verify(jwt, base64Security)) {
String userStr = new String(Base64.getUrlDecoder().decode(jwt.split("[.]")[1]));
return JSON.parseObject(userStr, LoginUser.class);
} else {
log.debug("JWT校验commons:verify()失败,校验失败");
}
return null;
}
/**
* 校验jwt
*/
public static LoginUser verifySignedAndGetUser(String jwt, String base64Security) {
if (StringUtils.isBlank(jwt)) {
log.debug("JWT校验commons:jwt为空,校验失败");
throw new IllegalArgumentException("jwt 不能为空");
}
if (StringUtils.isBlank(base64Security)) {
log.debug("JWT校验commons:base64Security为空,校验失败");
throw new IllegalArgumentException("key 不能为空");
}
if (veritySigned(jwt, base64Security)) {
String userStr = new String(Base64.getUrlDecoder().decode(jwt.split("[.]")[1]));
return JSON.parseObject(userStr, LoginUser.class);
} else {
log.debug("JWT校验commons:verify()失败,校验失败");
}
return null;
}
/**
* 获取加密算法
*/
private static SignatureAlgorithm getAlgorithm() {
return SignatureAlgorithm.HS256;
}
private static Key getKey(String base64Security, String algorithm) {
byte[] apiKeySecretBytes = Base64.getDecoder().decode(base64Security);
return new SecretKeySpec(apiKeySecretBytes, algorithm);
}
public static LoginUser checkAndGetUser(String authorization) {
//为空不合法
if (StringUtils.isBlank(authorization)) {
return null;
}
// 格式不合法
if (!authorization.startsWith("Bearer ")) {
return null;
}
String[] jwt = authorization.split("[.]");
if (jwt.length < 3) {
return null;
}
String payload = new String(Base64.getUrlDecoder().decode(jwt[1]));
if (StringUtils.isEmpty(payload)) {
return null;
}
return JSON.parseObject(payload, LoginUser.class);
}
private static Map<String, Object> user2map(LoginUser bean) {
Map<String, Object> map = new HashMap<>(16);
new BeanMap(bean).forEach((k, v) -> {
if ((v instanceof Long || v instanceof BigInteger) && v != null) {
map.put(String.valueOf(k), String.valueOf(v));
} else {
map.put(String.valueOf(k), v);
}
});
map.remove("authenticated");
return map;
}
}