package cn.ibizlab.util.security; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Clock; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.impl.DefaultClock; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.function.Function; @Component @ConditionalOnExpression("(!${ibiz.enablePermissionValid:false})&&'${ibiz.auth.token.util:UAATokenUtil}'.equals('SimpleTokenUtil')") public class SimpleTokenUtil implements AuthTokenUtil,Serializable { private static final long serialVersionUID = -3301605591108950415L; private Clock clock = DefaultClock.INSTANCE; @Value("${ibiz.jwt.secret:ibzsecret}") private String secret; @Value("${ibiz.jwt.expiration:7200000}") private Long expiration; @Value("${ibiz.jwt.header:Authorization}") 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); } public <T> T getClaimFromToken(String token, Function<Claims, T> 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<String, Object> claims = new HashMap<>(); return doGenerateToken(claims, userDetails.getUsername()); } private String doGenerateToken(Map<String, Object> 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) { AuthenticationUser user = (AuthenticationUser) userDetails; final Date created = getIssuedAtDateFromToken(token); return (!isTokenExpired(token) ); } private Date calculateExpirationDate(Date createdDate) { return new Date(createdDate.getTime() + expiration); } /** * Get the login of the current user. * * @return the login of the current user */ public static Optional<String> getCurrentUserLogin() { SecurityContext securityContext = SecurityContextHolder.getContext(); return Optional.ofNullable(securityContext.getAuthentication()) .map(authentication -> { if (authentication.getPrincipal() instanceof UserDetails) { UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); return springSecurityUser.getUsername(); } else if (authentication.getPrincipal() instanceof String) { return (String) authentication.getPrincipal(); } return null; }); } /** * Check if a user is authenticated. * * @return true if the user is authenticated, false otherwise */ public static boolean isAuthenticated() { SecurityContext securityContext = SecurityContextHolder.getContext(); return Optional.ofNullable(securityContext.getAuthentication()) .map(authentication -> authentication.getAuthorities().stream() .noneMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ANONYMOUS"))) .orElse(false); } /** * If the current user has a specific authority (security role). * <p> * The name of this method comes from the isUserInRole() method in the Servlet API * * @param authority the authority to check * @return true if the current user has the authority, false otherwise */ public static boolean isCurrentUserInRole(String authority) { SecurityContext securityContext = SecurityContextHolder.getContext(); return Optional.ofNullable(securityContext.getAuthentication()) .map(authentication -> authentication.getAuthorities().stream() .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(authority))) .orElse(false); } }