package com.jilongda.common.security;
|
|
import com.jilongda.common.basic.Constant;
|
import com.jilongda.common.exception.ServiceException;
|
import com.jilongda.common.exception.TokenException;
|
import com.jilongda.common.swagger.GlobalResultEnum;
|
import io.jsonwebtoken.*;
|
import io.jsonwebtoken.impl.DefaultClaims;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.util.Base64Utils;
|
import org.springframework.util.StringUtils;
|
|
import javax.servlet.http.HttpServletRequest;
|
import java.io.Serializable;
|
import java.util.*;
|
|
/**
|
* JWT工具类
|
*
|
* @author Louis
|
* @date Jun 29, 2019
|
*/
|
@Slf4j
|
public class JwtTokenUtils implements Serializable {
|
|
|
/**
|
* 用户名称
|
*/
|
private static final String USERNAME = Claims.SUBJECT;
|
|
/**
|
* 环境信息
|
*/
|
private static final String ENV = "env";
|
|
/**
|
* 用户主体信息
|
*/
|
private static final String USERID = "userId";
|
/**
|
* 创建时间
|
*/
|
private static final String CREATED = "created";
|
/**
|
* 权限列表
|
*/
|
private static final String AUTHORITIES = "authorities";
|
|
/**
|
* JWT Token 签发机构
|
*/
|
private static final String ISSUING_AGENCY = "Lingser Technology ISSUER";
|
/**
|
* JWT Token 默认的密钥
|
*/
|
private static final String SIGNING_KEY = "Lingser Technology SIGNING_KEY";
|
private static final long serialVersionUID = -576504484244573039L;
|
|
/**
|
* 从数据声明生成令牌
|
*
|
* @param payload 载荷
|
* @param tokenExpireTime
|
* @return
|
*/
|
private static String generateToken(Map<String, Object> payload, long tokenExpireTime) {
|
// token存在时间
|
Date expirationDate = new Date(System.currentTimeMillis() + tokenExpireTime * 1000L);
|
Claims claims = new DefaultClaims();
|
// 签发机构
|
claims.setIssuer(ISSUING_AGENCY);
|
// 载荷
|
claims.putAll(payload);
|
//
|
String token = Jwts.builder()
|
.setClaims(claims)
|
.setExpiration(expirationDate)
|
.signWith(SignatureAlgorithm.HS512, SIGNING_KEY)
|
.compact();
|
return token;
|
}
|
|
/**
|
* 生成token
|
*
|
* @param userName
|
* @param tokenExpireTime
|
* @return
|
*/
|
public static String generateToken(String userName, long tokenExpireTime) {
|
Map<String, Object> payload = new HashMap<>(2);
|
payload.put(USERNAME, userName);
|
payload.put(CREATED, new Date());
|
return generateToken(payload, tokenExpireTime);
|
}
|
|
/**
|
* 主要用于token不需要托管,但有多个场景的情况
|
* 生成token
|
*
|
* @param userName
|
* @param evn
|
* @param tokenExpireTime
|
* @return
|
*/
|
public static String generateToken(String userName, String evn, long tokenExpireTime) {
|
Map<String, Object> payload = new HashMap<>(3);
|
payload.put(USERNAME, userName);
|
payload.put(ENV, evn);
|
payload.put(CREATED, new Date());
|
return generateToken(payload, tokenExpireTime);
|
}
|
|
/**
|
* 从令牌中获取用户名
|
*
|
* @param token 令牌
|
* @return 用户名
|
*/
|
public static String getUsername(String token) {
|
Claims claims = getClaimsFromToken(token);
|
return claims.getSubject();
|
}
|
|
|
/**
|
* 根据请求令牌获取登录认证信息
|
*
|
* @param token
|
* @return
|
*/
|
public static Authentication getAuthenticatione(String token) {
|
Authentication authentication = getAuthentication();
|
if (StringUtils.hasLength(token)) {
|
// 上下文认证为空
|
if (Objects.isNull(authentication)) {
|
// 上下文中Authentication为空
|
Claims claims = getClaimsFromToken(token);
|
if (Objects.isNull(claims)) {
|
throw new ServiceException("从令牌中获取数据声明失败");
|
}
|
String username = claims.getSubject();
|
Object userDetails = claims.get(USERID);
|
if (!StringUtils.hasLength(username)) {
|
throw new ServiceException("获取用户名失败");
|
}
|
// 如果需要手动续期,此项判断需要注释
|
if (isTokenExpired(token)) {
|
throw new TokenException(GlobalResultEnum.TOKEN_EXPIRE.getCode(),GlobalResultEnum.TOKEN_EXPIRE.getMessage());
|
}
|
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
|
authentication = new UsernamePasswordAuthenticationToken(username, userDetails, authorities);
|
} else {
|
if (validateToken(token, getUsername())) {
|
// 如果上下文中Authentication非空,且请求令牌合法,直接返回当前登录认证信息
|
authentication = getAuthentication();
|
}
|
}
|
}
|
return authentication;
|
}
|
|
/**
|
* 从令牌中获取数据声明
|
* 解析JWT Token
|
*
|
* @param token 令牌
|
* @return 数据声明
|
*/
|
public static Claims getClaimsFromToken(String token) {
|
try {
|
// 传入令牌,判断accessToken是否存在
|
Claims claims = Jwts.parser().setSigningKey(SIGNING_KEY).parseClaimsJws(token).getBody();
|
return claims;
|
} catch (ExpiredJwtException e) {
|
log.error("Token 已过期");
|
throw new TokenException(GlobalResultEnum.TOKEN_EXPIRE.getCode(),GlobalResultEnum.TOKEN_EXPIRE.getMessage());
|
} catch (UnsupportedJwtException e) {
|
log.error("不支持的 Token");
|
throw new TokenException(GlobalResultEnum.TOKEN_PARSE_ERROR);
|
} catch (MalformedJwtException e) {
|
log.error("Token 无效");
|
throw new TokenException(GlobalResultEnum.TOKEN_PARSE_ERROR);
|
} catch (SignatureException e) {
|
log.error("无效的 Token 签名");
|
throw new TokenException(GlobalResultEnum.TOKEN_PARSE_ERROR);
|
} catch (IllegalArgumentException e) {
|
log.error("Token 参数不存在");
|
throw new TokenException(GlobalResultEnum.TOKEN_PARSE_ERROR);
|
} catch (TokenException e) {
|
log.error("Token 已过期");
|
throw new TokenException(GlobalResultEnum.TOKEN_EXPIRE.getCode(),GlobalResultEnum.TOKEN_EXPIRE.getMessage());
|
} catch (Exception e) {
|
log.error("token 解析失败,请尝试重新登录");
|
throw new TokenException(GlobalResultEnum.TOKEN_PARSE_ERROR);
|
}
|
|
}
|
|
|
/**
|
* 验证令牌
|
*
|
* @param token
|
* @param username
|
* @return
|
*/
|
public static Boolean validateToken(String token, String username) {
|
String userName = getUsername(token);
|
if (!StringUtils.hasLength(userName)) {
|
throw new IllegalArgumentException("请求令牌无效");
|
}
|
return (userName.equals(username) && !isTokenExpired(token));
|
}
|
|
|
/**
|
* 刷新令牌,重新生成
|
*
|
* @param token
|
* @return
|
*/
|
public static String refreshToken(String token, long tokenExpireTime) {
|
String refreshedToken;
|
try {
|
Claims claims = getClaimsFromToken(token);
|
String userName = claims.getSubject();
|
refreshedToken = generateToken(userName, tokenExpireTime);
|
} catch (Exception e) {
|
throw new SecurityException("刷新令牌出错!");
|
}
|
return refreshedToken;
|
}
|
|
/**
|
* 刷新令牌,重新生成
|
*
|
* @param token
|
* @param env
|
* @param tokenExpireTime
|
* @return
|
*/
|
public static String refreshToken(String token, String env, long tokenExpireTime) {
|
String refreshedToken;
|
try {
|
Claims claims = getClaimsFromToken(token);
|
String userName = claims.getSubject();
|
refreshedToken = generateToken(userName, env, tokenExpireTime);
|
} catch (Exception e) {
|
throw new SecurityException("刷新令牌出错!");
|
}
|
return refreshedToken;
|
}
|
|
/**
|
* 判断令牌是否过期
|
*
|
* @param token 令牌
|
* @return 是否过期
|
*/
|
public static Boolean isTokenExpired(String token) {
|
try {
|
Claims claims = getClaimsFromToken(token);
|
Date expiration = claims.getExpiration();
|
return expiration.before(new Date());
|
} catch (Exception e) {
|
return false;
|
}
|
}
|
|
/**
|
* 获取请求token
|
*
|
* @param request
|
* @return
|
*/
|
public static String getToken(HttpServletRequest request) {
|
String token = request.getHeader(Constant.DEF_TOKEN_HEADER);
|
String asToken = request.getHeader(Constant.ALIAS_TOKEN_HEADER);
|
// 如果这两个头部信息均不存在
|
if (!StringUtils.hasLength(token) && !StringUtils.hasLength(asToken)) {
|
throw new ServiceException("资源未认证,访问受限");
|
}
|
// token转换
|
if (!StringUtils.hasLength(token)) {
|
token = asToken;
|
}
|
String tokenHead = "Bearer ";
|
if (token.contains(tokenHead)) {
|
token = token.substring(tokenHead.length());
|
}
|
if (!StringUtils.hasLength(token)) {
|
throw new ServiceException("访问令牌不能为空");
|
}
|
// base64 解码
|
try {
|
token = new String(Base64Utils.decode(token.getBytes()));
|
} catch (IllegalArgumentException e) {
|
throw new IllegalArgumentException("无效的令牌");
|
}
|
return token;
|
}
|
|
|
|
/**
|
* 获取当前用户名
|
*
|
* @return
|
*/
|
public static String getUsername() {
|
String username = null;
|
Authentication authentication = getAuthentication();
|
if (Objects.nonNull(authentication)) {
|
Object principal = authentication.getPrincipal();
|
if (Objects.nonNull(principal)) {
|
username = (String) principal;
|
}
|
}
|
return username;
|
}
|
|
|
|
|
|
|
|
/**
|
* 获取当前用户信息id
|
*
|
* @return
|
*/
|
public static Object getUserInfo() {
|
Object userInfo = null;
|
Authentication authentication = getAuthentication();
|
if (Objects.nonNull(authentication)) {
|
userInfo = authentication.getDetails();
|
}
|
return userInfo;
|
}
|
|
/**
|
* 获取用户名
|
*
|
* @return
|
*/
|
public static String getUsername(Authentication authentication) {
|
String username = null;
|
if (Objects.nonNull(authentication)) {
|
Object principal = authentication.getPrincipal();
|
if (Objects.nonNull(principal) && principal instanceof UserDetails) {
|
username = (String) principal;
|
}
|
}
|
return username;
|
}
|
|
/**
|
* 获取当前登录信息
|
*
|
* @return
|
*/
|
public static Authentication getAuthentication() {
|
if (Objects.isNull(SecurityContextHolder.getContext())) {
|
return null;
|
}
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
return authentication;
|
}
|
|
}
|