package me.zhengjie.core.utils; import io.jsonwebtoken.*; import io.jsonwebtoken.impl.DefaultClock; import me.zhengjie.common.exception.BadRequestException; import me.zhengjie.core.security.JwtUser; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest; import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @Component public class JwtTokenUtil implements Serializable { private static final long serialVersionUID = -3301605591108950415L; private Clock clock = DefaultClock.INSTANCE; @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; @Value("${jwt.header}") private String tokenHeader; 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); } publicT getClaimFromToken(String token, Function claimsResolver) { final Claims claims = getAllClaimsFromToken(token); return claimsResolver.apply(claims); } private Claims getAllClaimsFromToken(String token) { return Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); } private 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(UserDetails userDetails) { Map claims = new HashMap<>(); 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, secret) .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, secret) .compact(); } public Boolean validateToken(String token, UserDetails userDetails) { JwtUser user = (JwtUser) userDetails; final String username = getUsernameFromToken(token); final Date created = getIssuedAtDateFromToken(token); //final Date expiration = getExpirationDateFromToken(token); return ( username.equals(user.getUsername()) && !isTokenExpired(token) && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate()) ); } public String getUserName(HttpServletRequest request){ String authToken = request.getHeader(tokenHeader); if(StringUtils.isEmpty(authToken)||authToken.length()<7){ throw new BadRequestException(HttpStatus.FORBIDDEN,"Token令牌无效"); } final String token = authToken.substring(7); String username = null; try { username = getUsernameFromToken(token); } catch (ExpiredJwtException e){ throw new BadRequestException(HttpStatus.UNAUTHORIZED,"Token令牌已过期"); } return username; } private Date calculateExpirationDate(Date createdDate) { return new Date(createdDate.getTime() + expiration); } }