愿君学长松,慎勿作桃李。这篇文章主要讲述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
@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);
推荐阅读
- #yyds干活盘点#1.2 HTML5新的Input类型
- #yyds干货盘点#Spring专题「技术原理」为大家介绍一下Spring中的Ant路径匹配工具组件AntPathMatcher
- #yyds干货盘点#web安全day44(进阶!使用Nmap+Wireshark理解端口扫描)
- 需要链接到分页的最后一页
- 元查询比较元键是否在指定范围内
- 列出在WordPress的类别/标签中写了一定数量帖子的作者
- javascript accordion / CSS无法正常工作
- 在我的WordPress主题文件中不断发现注入垃圾的PHP
- 在WordPress中,如何将自定义帖子类型的默认管理排序顺序设置为自定义列()