package cn.lili.common.security.token;
|
|
import cn.lili.cache.Cache;
|
import cn.lili.cache.CachePrefix;
|
import cn.lili.common.enums.ResultCode;
|
import cn.lili.common.exception.ServiceException;
|
import cn.lili.common.properties.JWTTokenProperties;
|
import cn.lili.common.security.AuthUser;
|
import cn.lili.common.security.enums.SecurityEnum;
|
import cn.lili.common.security.enums.UserEnums;
|
import com.google.gson.Gson;
|
import io.jsonwebtoken.*;
|
import io.jsonwebtoken.security.SignatureException;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Component;
|
|
import java.util.Date;
|
import java.util.concurrent.TimeUnit;
|
|
/**
|
* TokenUtil
|
*
|
* @author Chopper
|
* @version v1.0
|
* 2020-11-12 18:44
|
*/
|
@Component
|
public class TokenUtil {
|
@Autowired
|
private JWTTokenProperties tokenProperties;
|
@Autowired
|
private Cache cache;
|
|
/**
|
* 构建token
|
*
|
* @param authUser 私有声明
|
* @return TOKEN
|
*/
|
public Token createToken(AuthUser authUser) {
|
Token token = new Token();
|
//访问token
|
String accessToken = createToken(authUser, tokenProperties.getTokenExpireTime());
|
|
cache.put(CachePrefix.ACCESS_TOKEN.getPrefix(authUser.getRole(), authUser.getId()) + accessToken, 1,
|
tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);
|
//刷新token生成策略:如果是长时间有效的token(用于app),则默认15天有效期刷新token。如果是普通用户登录,则刷新token为普通token2倍数
|
Long expireTime = authUser.getLongTerm() ? 15 * 24 * 60L : tokenProperties.getTokenExpireTime() * 2;
|
String refreshToken = createToken(authUser, expireTime);
|
|
cache.put(CachePrefix.REFRESH_TOKEN.getPrefix(authUser.getRole(), authUser.getId()) + refreshToken, 1, expireTime, TimeUnit.MINUTES);
|
|
token.setAccessToken(accessToken);
|
token.setRefreshToken(refreshToken);
|
return token;
|
}
|
|
/**
|
* 刷新token
|
*
|
* @param oldRefreshToken 刷新token
|
* @return token
|
*/
|
public Token refreshToken(String oldRefreshToken) {
|
|
Claims claims;
|
try {
|
claims = Jwts.parser()
|
.setSigningKey(SecretKeyUtil.generalKeyByDecoders())
|
.parseClaimsJws(oldRefreshToken).getBody();
|
} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException |
|
IllegalArgumentException e) {
|
//token 过期 认证失败等
|
throw new ServiceException(ResultCode.USER_AUTH_EXPIRED);
|
}
|
|
//获取存储在claims中的用户信息
|
String json = claims.get(SecurityEnum.USER_CONTEXT.getValue()).toString();
|
AuthUser authUser = new Gson().fromJson(json, AuthUser.class);
|
UserEnums userEnums = authUser.getRole();
|
|
String username = authUser.getUsername();
|
//获取是否长期有效的token
|
boolean longTerm = authUser.getLongTerm();
|
|
|
//如果缓存中有刷新token &&
|
if (cache.hasKey(CachePrefix.REFRESH_TOKEN.getPrefix(userEnums, authUser.getId()) + oldRefreshToken)) {
|
Token token = new Token();
|
//访问token
|
String accessToken = createToken(authUser, tokenProperties.getTokenExpireTime());
|
cache.put(CachePrefix.ACCESS_TOKEN.getPrefix(userEnums, authUser.getId()) + accessToken, 1, tokenProperties.getTokenExpireTime(),
|
TimeUnit.MINUTES);
|
|
//如果是信任登录设备,则刷新token长度继续延长
|
Long expirationTime = tokenProperties.getTokenExpireTime() * 2;
|
if (longTerm) {
|
expirationTime = 60 * 24 * 15L;
|
authUser.setLongTerm(true);
|
}
|
|
//刷新token生成策略:如果是长时间有效的token(用于app),则默认15天有效期刷新token。如果是普通用户登录,则刷新token为普通token2倍数
|
String refreshToken = createToken(authUser, expirationTime);
|
|
cache.put(CachePrefix.REFRESH_TOKEN.getPrefix(userEnums, authUser.getId()) + refreshToken, 1, expirationTime, TimeUnit.MINUTES);
|
token.setAccessToken(accessToken);
|
token.setRefreshToken(refreshToken);
|
cache.remove(CachePrefix.REFRESH_TOKEN.getPrefix(userEnums, authUser.getId()) + oldRefreshToken);
|
return token;
|
} else {
|
throw new ServiceException(ResultCode.USER_AUTH_EXPIRED);
|
}
|
|
}
|
|
/**
|
* 生成token
|
*
|
* @param authUser jwt主体对象
|
* @param expirationTime 过期时间(分钟)
|
* @return token字符串
|
*/
|
private String createToken(AuthUser authUser, Long expirationTime) {
|
//JWT 生成
|
return Jwts.builder()
|
//jwt 私有声明
|
.claim(SecurityEnum.USER_CONTEXT.getValue(), new Gson().toJson(authUser))
|
//JWT的主体
|
.setSubject(authUser.getUsername())
|
//失效时间 当前时间+过期分钟
|
.setExpiration(new Date(System.currentTimeMillis() + expirationTime * 60 * 1000))
|
//签名算法和密钥
|
.signWith(SecretKeyUtil.generalKey())
|
.compact();
|
}
|
}
|