JwtHelper
token⼝令⽣成
一、生成token字符串
public static String createToken(Long userId, Integer userType) {
// 创建一个JWT生成器,并配置相关信息
String token = Jwts.builder()
.setSubject("YYGH-USER")// 设置JWT主题(通常是令牌的用途描述)
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))//设置JWT的过期时间
.claim("userId", userId)//添加一个名为 "userId" 的声明,用于存储用户ID
// .claim("userName", userName)
.claim("userType", userType)// 添加一个名为 "userType" 的声明,用于存储用户类型
.signWith(SignatureAlgorithm.HS512, tokenSignKey)// 使用HS512算法进行签名,并提供签名密钥
.compressWith(CompressionCodecs.GZIP) // 使用GZIP进行压缩(可选)
.compact(); // 构建JWT令牌并返回
return token;
}
逐行解释:
String token = Jwts.builder()
:创建一个JWT生成器。.setSubject("YYGH-USER")
:设置JWT的主题(subject),通常用于描述令牌的用途。在这里,主题被设置为 “YYGH-USER”,可能表示这是用于医院挂号系统(YYGH)的用户令牌。.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
:设置JWT的过期时间。tokenExpiration
可能是一个表示令牌有效期的时间间隔。在当前时间基础上加上有效期,以确定令牌何时过期。.claim("userId", userId)
:添加一个声明(claim)到JWT中。在这里,我们添加了一个名为 “userId” 的声明,用于存储用户的ID。声明是JWT中的一些附加数据。.claim("userType", userType)
:添加另一个声明,名为 “userType”,用于存储用户的类型信息。.signWith(SignatureAlgorithm.HS512, tokenSignKey)
:使用HS512算法对JWT进行签名,并提供签名密钥tokenSignKey
。签名是为了确保令牌的完整性和安全性,以防止被篡改。.compressWith(CompressionCodecs.GZIP)
:可选步骤,使用GZIP进行压缩。这可以减小令牌的大小,但不是必需的。.compact()
:构建JWT令牌并返回。
最终,这个方法会返回一个包含用户信息的JWT令牌,可以用于身份验证和授权,或者传递给其他系统以证明用户的身份和权限。
二、从token字符串获取userid
它用于从给定的JWT令牌字符串中提取用户ID:
//从token字符串获取userid
public static Long getUserId(String token) {
// 如果token为空或null,直接返回null
if (StringUtils.isEmpty(token))
return null;
// 解析JWT令牌
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
// 获取JWT中的声明(claims)
Claims claims = claimsJws.getBody();
// 从声明中获取用户ID(作为Integer类型)
Integer userId = (Integer) claims.get("userId");
// 返回用户ID的Long类型
return userId.longValue();
}
逐行解释:
if (StringUtils.isEmpty(token)) return null;
:首先检查输入的token是否为空或null,如果是的话,直接返回null,避免后续操作出错。Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
:解析JWT令牌。这里使用了JWT的解析器,设置了签名密钥tokenSignKey
来验证令牌的完整性,并使用parseClaimsJws
方法解析JWT字符串token
。Claims claims = claimsJws.getBody();
:获取JWT中的声明(claims),这包括了在创建令牌时添加的所有声明(例如,userId、userType等)。Integer userId = (Integer) claims.get("userId");
:从JWT声明中获取名为 “userId” 的声明的值。注意,这里获取到的是一个Integer
类型的用户ID。return userId.longValue();
:将Integer
类型的用户ID转换为Long
类型,并返回。
最终,这个方法返回从JWT令牌中提取的用户ID。这是一种常见的用法,用于从令牌中提取有关用户身份和权限的信息。如果令牌无效或不包含所需的信息,该方法会返回null或抛出异常,具体行为取决于JWT解析库的实现。
三、/从token字符串获取userType
//从token字符串获取userType
public static Integer getUserType(String token) {
if (StringUtils.isEmpty(token))
return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (Integer) (claims.get("userType"));
}
四、/从token字符串获取userName
//从token字符串获取userName
public static String getUserName(String token) {
if (StringUtils.isEmpty(token))
return "";
Jws<Claims> claimsJws= Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String) claims.get("userName");
}
五、判断token是否有效
public static boolean isExpiration(String token) {
try {
boolean isExpire = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody()
.getExpiration().before(new Date());
//没有过期,有效,返回false
return isExpire;
} catch (Exception e) {
//过期出现异常,返回true
return true;
}
}
解释:
getExpiration().before(new Date())
是一个日期比较表达式,用于检查某个日期是否在当前日期之前。以下是解释:
-
getExpiration()
:这是一个方法,通常用于从某个对象中获取日期(通常是一个日期时间对象)的过期时间。在上下文中,它可能用于获取JWT令牌的过期时间。 -
new Date()
:这是一个Java中用于创建表示当前日期和时间的对象的方法。new Date()
创建了一个包含当前日期和时间的Date
对象。 -
before(new Date())
:这是一个日期比较方法,通常用于检查一个日期是否在另一个日期之前。在这里,它用于检查getExpiration()
方法返回的日期是否在当前日期之前。
如果 getExpiration()
返回的日期早于(即在之前)当前日期,表达式将返回 true
,表示令牌已经过期。这是在JWT令牌的上下文中非常有用的,因为它允许您检查令牌是否有效或已过期。如果返回 true
,则通常需要重新进行身份验证或者拒绝使用过期的令牌。
六、刷新Token
/**
* 刷新Token
*
* @param token
* @return
*/
public String refreshToken(String token) {
String refreshedToken;
try {
// 解析原始令牌,获取令牌中的声明
final Claims claims = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody();
//使用原始令牌中的信息创建一个新的令牌
refreshedToken = JwtHelper.createToken(getUserId(token), getUserType(token));
} catch (Exception e) {
// 发生异常时,将刷新令牌设置为null
refreshedToken = null;
}
return refreshedToken;
}
String refreshedToken;
:声明一个字符串变量refreshedToken
,用于存储刷新后的令牌。try { ... } catch (Exception e) { ... }
:使用异常处理块来捕获可能发生的异常,例如JWT解析失败或其他问题。final Claims claims = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
:在try
块中,首先解析原始的JWT令牌token
。这里使用了JWT解析器,提供了签名密钥tokenSignKey
,并通过parseClaimsJws
方法解析JWT字符串。然后,使用getBody()
方法获取JWT中的声明(claims),这些声明包含在原始令牌中。refreshedToken = JwtHelper.createToken(getUserId(token), getUserType(token));
:使用原始令牌中的信息创建一个新的令牌。getUserId(token)
和getUserType(token)
分别用于从原始令牌中获取用户ID和用户类型,然后使用这些信息来创建新的令牌。这个新令牌被赋值给refreshedToken
。refreshedToken = null;
:如果在解析或创建令牌过程中发生异常(在catch
块中),则将refreshedToken
设置为null
,表示刷新失败或发生错误。return refreshedToken;
:最后,返回刷新后的令牌。如果刷新成功,它将包含新的信息;如果刷新失败,它将为null
。
七、整体代码
/**
* @ClAssName JwtHelper
* @Description token⼝令⽣成
* @Author 欧妮甲是神仙
* @Date 2023/9/30 21:{MINUTE}
*/
public class JwtHelper {
private static long tokenExpiration = 24 * 60 * 60 * 1000;
private static String tokenSignKey = "123456";
//⽣成token字符串
public static String createToken(Long userId, Integer userType) {
String token = Jwts.builder()
.setSubject("YYGH-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
// .claim("userName", userName)
.claim("userType", userType)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
//从token字符串获取userid
public static Long getUserId(String token) {
if (StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).
parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer) claims.get("userId");
return userId.longValue();
}
//从token字符串获取userType
public static Integer getUserType(String token) {
if (StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws
= Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws
(token);
Claims claims = claimsJws.getBody();
return (Integer) (claims.get("userType"));
}
//从token字符串获取userName
public static String getUserName(String token) {
if (StringUtils.isEmpty(token)) return "";
Jws<Claims> claimsJws
= Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws
(token);
Claims claims = claimsJws.getBody();
return (String) claims.get("userName");
}
//判断token是否有效
public static boolean isExpiration(String token) {
try {
boolean isExpire = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody()
.getExpiration().before(new Date());
//没有过期,有效,返回false
return isExpire;
} catch (Exception e) {
//过期出现异常,返回true
return true;
}
}
/**
* 刷新Token
*
* @param token
* @return
*/
public String refreshToken(String token) {
String refreshedToken;
try {
final Claims claims = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody();
refreshedToken = JwtHelper.createToken(getUserId(token), getUserType(token));
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
}
八、应用
/**
* @ClAssName AuthContextHolder
* @Description 从request请求中获取token⼝令
* @Author 欧妮甲是神仙
* @Date 2023/9/30 22:{MINUTE}
*/
public class AuthContextHolder {
//从请求头token·获取userid
public static Long getUserIdToken(HttpServletRequest request) {
//从请求头token
String token = request.getHeader("token");
//调⽤⼯具类
Long userId = JwtHelper.getUserId(token);
return userId;
}
//从请求头token获取name
public static String getUserName(HttpServletRequest request) {
//从header获取token
String token = request.getHeader("token");
//jwt从token获取username
String userName = JwtHelper.getUserName(token);
return userName;
}
}