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 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 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 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 authorities = new ArrayList(); 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; } }