package pwc.taxtech.atms.security; import java.util.ArrayList; import java.util.Date; import java.util.List; import io.jsonwebtoken.*; import org.nutz.lang.Times; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import io.jsonwebtoken.impl.DefaultClaims; import io.jsonwebtoken.impl.DefaultJws; import io.jsonwebtoken.lang.Assert; import pwc.taxtech.atms.common.AtmsApiSettings; import pwc.taxtech.atms.common.CommonUtils; @Component public class JwtUtil implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class); @Autowired private AtmsApiSettings atmsApiSettings; @Value("${jwt.expireSecond}") private Integer jwtExpireSecond; @Override public void afterPropertiesSet() throws Exception { Assert.notNull(atmsApiSettings); Assert.hasText(atmsApiSettings.getJwtBase64Secret(), "Missing settings of jwt.secret"); jwtBase64Secret = atmsApiSettings.getJwtBase64Secret(); jwtPowerToken = atmsApiSettings.getJwtPowerToken(); } /** * The BASE64-encoded algorithm-specific signing key to use to digitally sign * the JWT */ private String jwtBase64Secret; private String jwtPowerToken; @SuppressWarnings({ "unchecked", "rawtypes" }) public JwtUser parseToken(String token) { if (StringUtils.hasText(jwtPowerToken) && jwtPowerToken.equals(token)) { return new JwtUser("test_userid", "admin", "Admin", null, getAuthorities()); } JwtParser parser = Jwts.parser().setSigningKey(jwtBase64Secret); Jwt jwt = parser.parseClaimsJws(token); DefaultJws<DefaultClaims> defaultJws = (DefaultJws<DefaultClaims>) jwt; DefaultClaims defaultClaims = defaultJws.getBody(); String databaseUsername = String.valueOf(defaultClaims.get("databaseUsername")); String username = String.valueOf(defaultClaims.get("username")); String userid = String.valueOf(defaultClaims.get("userid")); return new JwtUser(userid, username, databaseUsername, defaultClaims, getAuthorities()); } private List<SimpleGrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> list = new ArrayList<>(); list.add(new SimpleGrantedAuthority("ROLE_USER")); list.add(new SimpleGrantedAuthority("ROLE_JWT_USER")); return list; } /*** * @param username * 登录名,大小写不限,可以是全大写或全小写,如:admin, ADMIN * @param databaseUsername * 数据库用户名, 比如Admin * @param userid * 用户Id * @return */ public String generateToken(String username, String databaseUsername, String userid) { // sub: 该JWT所面向的用户 // iss: 该JWT的签发者 // iat(issued at): 在什么时候签发的token // exp(expires): token什么时候过期 // nbf(not before):token在此时间之前不能被接收处理 // jti:JWT Id为web token提供唯一标识 Date now = new Date(); // 过期时间设置为2天 int expireSecond = jwtExpireSecond; Date expiration = Times.nextSecond(now, expireSecond); JwtBuilder jwtBuilder = Jwts.builder(); // 设置Subject为登录用户名 jwtBuilder.setSubject(username); jwtBuilder.setExpiration(expiration); jwtBuilder.setIssuedAt(now); // 设置时钟误差偏移量,即10分钟 Date notBefore = Times.nextSecond(now, -600); jwtBuilder.setNotBefore(notBefore); jwtBuilder.setId(CommonUtils.getUUID()); jwtBuilder.claim("username", username); jwtBuilder.claim("databaseUsername", databaseUsername); jwtBuilder.claim("userid", userid); // 设置body.username为数据库用户名 jwtBuilder.signWith(SignatureAlgorithm.HS512, jwtBase64Secret); return jwtBuilder.compact(); } public String getJwtBase64Secret() { return jwtBase64Secret; } public void setJwtBase64Secret(String jwtBase64Secret) { this.jwtBase64Secret = jwtBase64Secret; } public String getJwtPowerToken() { return jwtPowerToken; } public void setJwtPowerToken(String jwtPowerToken) { this.jwtPowerToken = jwtPowerToken; } }