package com.artfess.base.jwt; import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Function; import javax.annotation.Resource; import com.artfess.base.cache.annotation.CacheEvict; import com.artfess.base.cache.annotation.CachePut; import com.artfess.base.cache.annotation.Cacheable; import com.artfess.base.cache.annotation.FirstCache; import com.artfess.base.cache.annotation.SecondaryCache; import com.artfess.base.conf.JwtConfig; import com.artfess.base.constants.CacheKeyConst; import com.artfess.base.constants.SystemConstants; import com.artfess.base.context.BaseContext; import com.artfess.base.util.AppUtil; import com.artfess.base.util.StringUtil; import com.artfess.uc.api.model.IUser; import com.artfess.uc.api.service.IUserService; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Clock; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.impl.DefaultClock; @Component public class JwtTokenHandler implements Serializable { @Resource JwtConfig jwtConfig; static final String CLAIM_KEY_USERNAME = "sub"; static final String CLAIM_KEY_CREATED = "iat"; private static final long serialVersionUID = -3301605591108950415L; private Clock clock = DefaultClock.INSTANCE; public String getUsernameFromToken(String token) { return getClaimFromToken(token, Claims::getSubject); } public Date getIssuedAtDateFromToken(String token) { return getClaimFromToken(token, Claims::getIssuedAt); } public Date getExpirationDateFromToken(String token) { return getClaimFromToken(token, Claims::getExpiration); } public T getClaimFromToken(String token, Function claimsResolver) { final Claims claims = getAllClaimsFromToken(token); return claimsResolver.apply(claims); } private Claims getAllClaimsFromToken(String token) { return Jwts.parser() .setSigningKey(jwtConfig.getSecret()) .parseClaimsJws(token) .getBody(); } public Boolean isTokenExpired(String token) { final Date expiration = getExpirationDateFromToken(token); return expiration.before(clock.now()); } private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) { return (lastPasswordReset != null && created.before(lastPasswordReset)); } private Boolean ignoreTokenExpiration(String token) { // here you specify tokens, for that the expiration is ignored return false; } public String generateToken(String userAccount) { IUserService userService = AppUtil.getBean(IUserService.class); IUser userByAccount = userService.getUserByAccount(userAccount); Assert.notNull(userByAccount, String.format("根据所传账号【%s】未查询到用户", userAccount)); return generateToken(userByAccount); } public String generateToken(UserDetails userDetails) { Map claims = new HashMap<>(); String tenantId = ""; String userId = ""; if(userDetails instanceof IUser ) { IUser iUser = (IUser) userDetails; tenantId = iUser.getTenantId(); userId = iUser.getUserId(); } claims.put("tenantId", tenantId); claims.put("userId", userId); return doGenerateToken(claims, userDetails.getUsername()); } private String doGenerateToken(Map claims, String subject) { final Date createdDate = clock.now(); final Date expirationDate = calculateExpirationDate(createdDate); return Jwts.builder() .setClaims(claims) .setSubject(subject) .setIssuedAt(createdDate) .setExpiration(expirationDate) .signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret()) .compact(); } public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) { final Date created = getIssuedAtDateFromToken(token); return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset) && (!isTokenExpired(token) || ignoreTokenExpiration(token)); } public String refreshToken(String token) { final Date createdDate = clock.now(); final Date expirationDate = calculateExpirationDate(createdDate); final Claims claims = getAllClaimsFromToken(token); claims.setIssuedAt(createdDate); claims.setExpiration(expirationDate); return Jwts.builder() .setClaims(claims) .signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret()) .compact(); } @SuppressWarnings("unused") public Boolean validateToken(String token, UserDetails userDetails) { final String username = getUsernameFromToken(token); final Date created = getIssuedAtDateFromToken(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } private Date calculateExpirationDate(Date createdDate) { return new Date(createdDate.getTime() + jwtConfig.getExpiration() * 1000); } public String getTenantIdFromToken(String authToken) { Claims allClaimsFromToken = getAllClaimsFromToken(authToken); String tenantId = allClaimsFromToken.get("tenantId", String.class); return tenantId; } public String getUserIdFromToken(String authToken) { Claims allClaimsFromToken = getAllClaimsFromToken(authToken); String userId = allClaimsFromToken.get("userId", String.class); return userId; } /** *
feign token 
*/ public String generateFeignToken() { BaseContext baseContext = AppUtil.getBean(BaseContext.class); Map claims = new HashMap<>(); String currentUserId = baseContext.getCurrentUserId(); String currentUserAccout = baseContext.getCurrentUserAccout(); if ("-1".equals(currentUserAccout) || StringUtil.isEmpty(currentUserAccout)) { currentUserAccout = SystemConstants.SYSTEM_ACCOUNT; } String tenantId = baseContext.getCurrentTenantId(); /* if("-1".equals(tenantId)){ claims.put("userId",currentUserId ); }*/ claims.put("userId", currentUserId); claims.put("tenantId", tenantId); return doGenerateFeignToken(claims,currentUserAccout); } private String doGenerateFeignToken(Map claims, String subject) { final Date createdDate = clock.now(); final Date expirationDate = calculateFeignExpirationDate(createdDate); return Jwts.builder() .setClaims(claims) .setSubject(subject) .setIssuedAt(createdDate) .setExpiration(expirationDate) .signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret()) .compact(); } @SuppressWarnings("unused") public Boolean validateFeignToken(String token) { final String username = getUsernameFromToken(token); BaseContext baseContext = AppUtil.getBean(BaseContext.class); final Date created = getIssuedAtDateFromToken(token); return (username.equals(baseContext.getCurrentUserAccout()) && !isTokenExpired(token)); } /** *
	 * feign 请求的token 设置有效时间默认为1天
	 * 
* @param createdDate * @return */ private Date calculateFeignExpirationDate(Date createdDate) { return new Date(createdDate.getTime() + jwtConfig.getExpiration() * 1000); } /** * 获取缓存中的token * @param userAgent * @param tenantId * @param account * @param expireTime * @return */ @Cacheable(value = CacheKeyConst.EIP_UC_USER_TOKEN, key = "#userAgent+'_'+#tenantId+'_'+#account", ignoreException = false, firstCache = @FirstCache(expireTime = 1800, expireTimeExp = "#expireTime", timeUnit = TimeUnit.SECONDS), secondaryCache = @SecondaryCache(expireTime = 1800, expireTimeExp = "#expireTime", preloadTime = 360, forceRefresh = true, timeUnit = TimeUnit.SECONDS)) public String getTokenFromCache(String userAgent, String tenantId, String account, int expireTime) { return null; } /** * 将token缓存起来 * @param userAgent * @param tenantId * @param account * @param expireTime * @param token * @return */ @CachePut(value = CacheKeyConst.EIP_UC_USER_TOKEN, key = "#userAgent+'_'+#tenantId+'_'+#account", ignoreException = false, firstCache = @FirstCache(expireTime = 1800, expireTimeExp = "#expireTime", timeUnit = TimeUnit.SECONDS), secondaryCache = @SecondaryCache(expireTime = 1800, expireTimeExp = "#expireTime", preloadTime = 360, forceRefresh = true, timeUnit = TimeUnit.SECONDS)) public String putTokenInCache(String userAgent, String tenantId, String account, int expireTime, String token) { return token; } /** * 删除token *

可实现服务端踢用户下线

* @param userAgent * @param tenantId * @param account */ @CacheEvict(value = CacheKeyConst.EIP_UC_USER_TOKEN, key = "#userAgent+'_'+#tenantId+'_'+#account", ignoreException = false) public void removeFromCache(String userAgent, String tenantId, String account) { } /** * 将token缓存起来 * @param userAgent * @param tenantId * @param account * @param expireTime * @param token * @return */ @CachePut(value = CacheKeyConst.EIP_UC_USER_TOKEN, key = "#userAgent+'_'+#tenantId+'_'+#account+'_'+#ip", ignoreException = false, firstCache = @FirstCache(expireTime = 1800, expireTimeExp = "#expireTime", timeUnit = TimeUnit.SECONDS), secondaryCache = @SecondaryCache(expireTime = 1800, expireTimeExp = "#expireTime", preloadTime = 360, forceRefresh = true, timeUnit = TimeUnit.SECONDS)) public String putTokenInCache(String userAgent, String tenantId, String account,String ip, int expireTime, String token) { return token; } /** * 删除token *

可实现服务端踢用户下线

* @param userAgent * @param tenantId * @param account */ @CacheEvict(value = CacheKeyConst.EIP_UC_USER_TOKEN, key = "#userAgent+'_'+#tenantId+'_'+#account+'_'+#ip", ignoreException = false) public void removeFromCache(String userAgent, String tenantId, String account,String ip) { } // public static void main(String[] args) { // JwtTokenHandler jwtTokenHandler=new JwtTokenHandler(); // System.out.println(jwtTokenHandler.getUsernameFromToken("eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2MjUyMDQxODcsImlhdCI6MTYyNTExNzc4N30.uu5Ixf0wIEwALT72bCmB-mSklCBMRQA7xQTJAxVTYv3w-pFFjopWEQlXZdQAt0SHryh4c93MahXS7wbYLGunUg")); // } }