package com.ycl.utils;
|
|
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.util.StrUtil;
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONObject;
|
import com.ycl.entity.auth.AuthInfo;
|
import com.ycl.enums.common.ResultCode;
|
import com.ycl.exception.ApiException;
|
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.SignatureAlgorithm;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Value;
|
|
import java.util.Date;
|
import java.util.HashMap;
|
import java.util.Map;
|
|
/**
|
* JwtToken生成的工具类
|
* JWT token的格式:header.payload.signature
|
* header的格式(算法、token的类型):
|
* {"alg": "HS512","typ": "JWT"}
|
* payload的格式(用户名、创建时间、生成时间):
|
* {"sub":"wang","created":1489079981393,"exp":1489684781}
|
* signature的生成算法:
|
* HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
|
* Created by macro on 2018/4/26.
|
*/
|
public class JwtTokenUtil {
|
private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);
|
private static final String CLAIM_KEY_INFO = "sub";
|
private static final String CLAIM_KEY_CREATED = "created";
|
|
private final String secret = "qwezxcasd";
|
|
private Long expiration=2592000L;
|
@Value("${jwt.tokenHead}")
|
private String tokenHead;
|
|
/**
|
* 根据负责生成JWT的token
|
*/
|
private String generateToken(Map<String, Object> claims) {
|
return Jwts.builder()
|
.setClaims(claims)
|
.setExpiration(generateExpirationDate())
|
.signWith(SignatureAlgorithm.HS512, secret)
|
.compact();
|
}
|
|
/**
|
* 从token中获取JWT中的负载
|
*/
|
private Claims getClaimsFromToken(String token) {
|
Claims claims = null;
|
try {
|
claims = Jwts.parser()
|
.setSigningKey(secret)
|
.parseClaimsJws(token)
|
.getBody();
|
} catch (Exception e) {
|
LOGGER.info("JWT格式验证失败:{}", token);
|
}
|
return claims;
|
}
|
|
/**
|
* 生成token的过期时间
|
*/
|
private Date generateExpirationDate() {
|
return new Date(System.currentTimeMillis() + expiration * 1000);
|
}
|
|
/**
|
* 从token中获取登录用户名
|
*/
|
public String getUserNameFromToken(String token) {
|
String username;
|
try {
|
Claims claims = getClaimsFromToken(token);
|
username = claims.getSubject();
|
} catch (Exception e) {
|
username = null;
|
}
|
return username;
|
}
|
|
/**
|
* 验证token是否还有效
|
*
|
* @param token 客户端传入的token
|
* @param userDetails 从数据库中查询出来的用户信息
|
*/
|
// public boolean validateToken(String token, UserDetails userDetails) {
|
// String username = parseToken(token).getUsername();
|
// return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
|
// }
|
|
/**
|
* 判断token是否已经失效
|
*/
|
private boolean isTokenExpired(String token) {
|
Date expiredDate = getExpiredDateFromToken(token);
|
return expiredDate.before(new Date());
|
}
|
|
/**
|
* 从token中获取过期时间
|
*/
|
private Date getExpiredDateFromToken(String token) {
|
Claims claims = getClaimsFromToken(token);
|
return claims.getExpiration();
|
}
|
|
/**
|
* 根据用户信息生成token
|
*/
|
// public String generateToken(UserDetails userDetails) {
|
// Map<String, Object> claims = new HashMap<>();
|
// claims.put(CLAIM_KEY_INFO, userDetails.getUsername());
|
// claims.put(CLAIM_KEY_CREATED, new Date());
|
// return generateToken(claims);
|
// }
|
|
/**
|
* 当原来的token没过期时是可以刷新的
|
*
|
* @param oldToken 带tokenHead的token
|
*/
|
public String refreshHeadToken(String oldToken) {
|
if (StrUtil.isEmpty(oldToken)) {
|
return null;
|
}
|
String token = oldToken.substring(tokenHead.length());
|
if (StrUtil.isEmpty(token)) {
|
return null;
|
}
|
//token校验不通过
|
Claims claims = getClaimsFromToken(token);
|
if (claims == null) {
|
return null;
|
}
|
//如果token已经过期,不支持刷新
|
if (isTokenExpired(token)) {
|
return null;
|
}
|
//如果token在30分钟之内刚刷新过,返回原token
|
if (tokenRefreshJustBefore(token, 30 * 60)) {
|
return token;
|
} else {
|
claims.put(CLAIM_KEY_CREATED, new Date());
|
return generateToken(claims);
|
}
|
}
|
|
/**
|
* 判断token在指定时间内是否刚刚刷新过
|
*
|
* @param token 原token
|
* @param time 指定时间(秒)
|
*/
|
private boolean tokenRefreshJustBefore(String token, int time) {
|
Claims claims = getClaimsFromToken(token);
|
Date created = claims.get(CLAIM_KEY_CREATED, Date.class);
|
Date refreshDate = new Date();
|
//刷新时间在创建时间的指定时间内
|
if (refreshDate.after(created) && refreshDate.before(DateUtil.offsetSecond(created, time))) {
|
return true;
|
}
|
return false;
|
}
|
|
|
/**
|
* 根据用户id,用户名生成token
|
*/
|
public String generateToken(long userId, String username) {
|
Map<String, Object> claims = new HashMap<>();
|
AuthInfo authInfo = new AuthInfo();
|
authInfo.setUserId(userId);
|
authInfo.setUsername(username);
|
claims.put(CLAIM_KEY_INFO, JSONObject.toJSONString(authInfo));
|
claims.put(CLAIM_KEY_CREATED, new Date());
|
return generateToken(claims);
|
}
|
|
/**
|
* 根据token解析出AuthInfo
|
*
|
* @param token
|
* @return
|
*/
|
public AuthInfo parseToken(String token) {
|
AuthInfo authInfo = null;
|
try {
|
if (isTokenExpired(token)) {
|
throw new ApiException(ResultCode.NOT_LOGGED);
|
}
|
Claims claims = getClaimsFromToken(token);
|
String subject = claims.getSubject();
|
authInfo = JSON.parseObject(subject, AuthInfo.class);
|
} catch (Exception e) {
|
throw new ApiException(e.getMessage());
|
}
|
return authInfo;
|
}
|
}
|