JWT 工具类#yyds干货盘点#

愿君学长松,慎勿作桃李。这篇文章主要讲述JWT 工具类#yyds干货盘点#相关的知识,希望能为你提供帮助。
【JWT 工具类#yyds干货盘点#】生成JWT
解析JWT
第一步:创建SpringBoot项目

  • 添加依赖
< dependency> < groupId> org.projectlombok< /groupId> < artifactId> lombok< /artifactId> < version> 1.18.22< /version> < /dependency> < dependency> < groupId> io.jsonwebtoken< /groupId> < artifactId> jjwt-api< /artifactId> < version> 0.11.2< /version> < /dependency> < dependency> < groupId> io.jsonwebtoken< /groupId> < artifactId> jjwt-impl< /artifactId> < version> 0.11.2< /version> < scope> runtime< /scope> < /dependency> < dependency> < groupId> io.jsonwebtoken< /groupId> < artifactId> jjwt-jackson< /artifactId> < version> 0.11.2< /version> < scope> runtime< /scope> < /dependency> < dependency> < groupId> org.springframework.boot< /groupId> < artifactId> spring-boot-starter-security< /artifactId> < /dependency>

  • 修改配置文件application.yml
    jwt: # 为JWT基础信息加密和解密的密钥,长度需要大于等于43 # 在实际生产中通常不直接写在配置文件里面。而是通过应用的启动参数传递,并且需要定期修改 secret: oQZSeguYloAPAmKwvKqqnifiQatxMEPNOvtwPsCLasd # JWT令牌的有效时间,单位秒,默认2周 expiration: 1209600 header: Authorization prefix: hc

第二步:创建JWT工具类
@Slf4j @Component @ConfigurationProperties(prefix = "jwt") public class JwtUtil /** * 携带JWT令牌的HTTP的Header的名称,在实际生产中可读性越差越安全 */ @Getter @Value("$header") private String header; /** * */ @Getter @Value("$prefix") private String prefix; /** * 为JWT基础信息加密和解密的密钥 * 在实际生产中通常不直接写在配置文件里面。而是通过应用的启动参数传递,并且需要定期修改。 */ @Value("$secret") private String secret; /** * JWT令牌的有效时间,单位秒 * - 默认2周 */ @Value("$expiration") private Long expiration; /** * SecretKey 根据 SECRET 的编码方式解码后得到: * Base64 编码:SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString)); * Base64URL 编码:SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64URL.decode(secretString)); * 未编码:SecretKey key = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8)); */ private static SecretKey getSecretKey(String secret) byte[] encodeKey = Decoders.BASE64.decode(secret); return Keys.hmacShaKeyFor(encodeKey); /** * 用claims生成token * * @param claims 数据声明,用来创建payload的私有声明 * @return token 令牌 */ private String generateToken(Map< String, Object> claims) SecretKey key = getSecretKey(secret); //SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //两种方式等价// 添加payload声明 JwtBuilder jwtBuilder = Jwts.builder() // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的 .setClaims(claims) // 设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。 .setId(UUID.randomUUID().toString()) // iat: jwt的签发时间 .setIssuedAt(new Date())// 你也可以改用你喜欢的算法,支持的算法详见:https://github.com/jwtk/jjwt#features // SignatureAlgorithm.HS256:指定签名的时候使用的签名算法,也就是header那部分 .signWith(key, SignatureAlgorithm.HS256) .setExpiration(new Date(System.currentTimeMillis() + this.expiration * 1000)); String token = jwtBuilder.compact(); return token; /** * 生成Token令牌 * * @param userDetails 用户 * @return 令牌Token */ public String generateToken(UserDetails userDetails) Map< String, Object> claims = new HashMap< > (); claims.put("sub", userDetails.getUsername()); claims.put("created", new Date()); return generateToken(claims); /** * 从token中获取数据声明claim * * @param token 令牌token * @return 数据声明claim */ public Claims getClaimsFromToken(String token) try SecretKey key = getSecretKey(secret); Claims claims = Jwts.parser() .setSigningKey(key) .parseClaimsJws(token) .getBody(); return claims; catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) log.error("token解析错误", e); throw new IllegalArgumentException("Token invalided."); /** * 从token中获取登录用户名 * * @param token 令牌 * @return 用户名 */ public String getUsernameFromToken(String token) String username; try Claims claims = getClaimsFromToken(token); username = claims.getSubject(); catch (Exception e) username = null; return username; /** * 获取token的过期时间 * * @param token token * @return 过期时间 */ public Date getExpirationFromToken(String token) return getClaimsFromToken(token).getExpiration(); /** * 判断token是否过期 * * @param token 令牌 * @return 是否过期:已过期返回true,未过期返回false */ public Boolean isTokenExpired(String token) Date expiration = getExpirationFromToken(token); return expiration.before(new Date()); /** * 验证令牌:判断token是否非法 * * @param token令牌 * @param userDetails 用户 * @return 如果token未过期且合法,返回true,否则返回false */ public Boolean validateToken(String token, UserDetails userDetails) //如果已经过期返回false if (isTokenExpired(token)) return false; String usernameFromToken = getUsernameFromToken(token); String username = userDetails.getUsername(); return username.equals(usernameFromToken);

第三步:SpringSecurity配置文件注入PasswordEncoder
@Configuration public class SpringSecurityConfig extends WebSecurityConfigurerAdapter @Bean public PasswordEncoder passwordEncoder() return new BCryptPasswordEncoder();

第四步:工具类测试
@SpringBootTest public class JwtUtilTest @Resource private JwtUtil jwtUtil; @Resource private PasswordEncoder passwordEncoder; @Test void fun() System.out.println(passwordEncoder); SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256); System.out.println(secretKey); //生成token @Test void generateToken() //用户信息 String encode = passwordEncoder.encode("1234"); User user = new User("zhangsan", encode, AuthorityUtils.createAuthorityList()); String token = jwtUtil.generateToken(user); System.out.println(token); @Test void getClaimsFromToken() //用户信息 String encode = passwordEncoder.encode("1234"); User user = new User("zhangsan", encode, AuthorityUtils.createAuthorityList()); String token = jwtUtil.generateToken(user); System.out.println(token); Claims claims = jwtUtil.getClaimsFromToken(token); System.out.println(claims); @Test void getSubjectFromToken() //用户信息 String encode = passwordEncoder.encode("1234"); User user = new User("zhangsan", encode, AuthorityUtils.createAuthorityList()); String token = jwtUtil.generateToken(user); System.out.println(token); String username = jwtUtil.getSubjectFromToken(token); System.out.println(username); @Test void getExpirationFromToken() //用户信息 String encode = passwordEncoder.encode("1234"); User user = new User("zhangsan", encode, AuthorityUtils.createAuthorityList()); String token = jwtUtil.generateToken(user); System.out.println(token); Date date = jwtUtil.getExpirationFromToken(token); System.out.println(new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(date)); @Test void isTokenExpired() //用户信息 String encode = passwordEncoder.encode("1234"); User user = new User("zhangsan", encode, AuthorityUtils.createAuthorityList()); String token = jwtUtil.generateToken(user); System.out.println(token); Boolean res = jwtUtil.isTokenExpired(token); System.out.println(res); @Test void validateToken() //用户信息 String encode = passwordEncoder.encode("1234"); User user = new User("zhangsan", encode, AuthorityUtils.createAuthorityList()); String token = jwtUtil.generateToken(user); System.out.println(token); User user2 = new User("zhangsan", "", AuthorityUtils.createAuthorityList()); Boolean res = jwtUtil.validateToken(token,user2); System.out.println(res); //模拟篡改 @Test void fake() // 将我改成你生成的token的第一段(以.为边界) String encodedHeader = "eyJhbGciOiJIUzI1NiJ9"; // 测试4: 解密Header byte[] header = Base64.decodeBase64(encodedHeader.getBytes()); System.out.println(new String(header)); // 将我改成你生成的token的第二段(以.为边界) String encodedPayload = "eyJpZCI6IjEiLCJpYXQiOjE1NjU1ODk1NDEsImV4cCI6MTU2Njc5OTE0MX0"; // 测试5: 解密Payload byte[] payload = Base64.decodeBase64(encodedPayload.getBytes()); System.out.println(new String(payload)); //用户信息 String encode = passwordEncoder.encode("1234"); User user = new User("zhangsan", encode, AuthorityUtils.createAuthorityList()); // 测试6: 这是一个被篡改的token,因此会报异常,说明JWT是安全的 jwtUtil.validateToken("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEiLCJpYXQiOjE1NjU1ODk3MzIsImV4cCI6MTU2Njc5OTMzMn0.nDv25ex7XuTlmXgNzGX46LqMZItVFyNHQpmL9UQf-aUx",user);


    推荐阅读