Jwt
概念:
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的 一 种 基 于 J S O N \textcolor{red}{一种基于JSON} 一种基于JSON的开放标准((RFC 7519).该token被设计为 紧 凑 且 安 全 \textcolor{red}{紧凑且安全} 紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在 身 份 提 供 者 和 服 务 提 供 者 间 传 递 \textcolor{red}{身份提供者和服务提供者间传递} 身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token 也可直接被用于认证,也可被加密
\textcolor{red}{}
JWT的认证流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TutUz6OI-1652966782320)(C:\Users\yuxua\AppData\Roaming\Typora\typora-user-images\image-20220514170059385.png)]
流程说明
1,浏览器发起请求登陆,携带用户名和密码;
2,服务端验证身份,根据算法,将用户标识符打包生成 token,
3,服务器返回JWT信息给浏览器,JWT不包含敏感信息;
4,浏览器发起请求获取用户资料,把刚刚拿到的 token一起发送给服务器;
5,服务器发现数据中有 token,验明正身;
6,服务器返回该用户的用户资料;
token与session的区别
session
Session是存放在服务器端的,可以保存在:内存、数据库、NoSQL中。它采用 空 间 换 时 间 的 策 略 \textcolor{red}{空间换时间的策略} 空间换时间的策略来进行身份识别,若Session没有持久化落地存储,一旦服务器重启,Session数据会丢失。
token
Token是放在客户端存储的,采用了 时 间 换 空 间 策 略 \textcolor{red}{时间换空间策略} 时间换空间策略,token类似一个令牌它也是无状态的,用户信息都被加密到token中,服务器收到token后解密就可知道是哪个用户。所以在分布式环境中应用广泛。
适用场景
一般购物车功能会采用Session验证,接口校验一般会采用Token验证,具体采用何种方法,需要大家根据自己的业务进行选择。
JwtToken工具
配置yml文件
eshop:
security:
jwt-key: eshopmini
token-expired-in: 86400000
工具类
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* @ClassName JwtToken
* @Author zhonghui
* @Date 2020/4/30
**/
@Component
public class JwtToken {
private static String jwtKey;
private static Integer expiredTimeIn;
private static Integer defaultScope = 8;
@Value("${eshop.security.jwt-key}")
public void setJwtKey(String jwtKey) {
JwtToken.jwtKey = jwtKey;
}
@Value("${eshop.security.token-expired-in}")
public void setExpiredTimeIn(Integer expiredTimeIn) {
JwtToken.expiredTimeIn = expiredTimeIn;
}
/**
* 获取自定义数据
* @param token
* @return
*/
public static Optional<Map<String, Claim>> getClaims(String token) {
DecodedJWT decodedJWT;
// 指定算法
Algorithm algorithm = Algorithm.HMAC256(JwtToken.jwtKey); // 编码
JWTVerifier jwtVerifier = JWT.require(algorithm).build();
try {
decodedJWT = jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
return Optional.empty();
}
return Optional.of(decodedJWT.getClaims());
}
/**
* 验证Token
* @param token
* @return
*/
public static Boolean verifyToken(String token) {
try {
Algorithm algorithm = Algorithm.HMAC256(JwtToken.jwtKey);
JWTVerifier verifier = JWT.require(algorithm).build();
verifier.verify(token);
} catch (JWTVerificationException e) {
return false;
}
return true;
}
// 获得过期时间
public static String getExpireTime(String token){
return DateUtil.formatDateTime(JWT.decode(token).getExpiresAt()); // 解码
}
// 生成令牌
public static String makeToken(Long uid,String uName, Integer scope) {
return JwtToken.getToken(uid,uName, scope);
}
// 生成令牌
public static String makeToken(Long uid,String uName) {
return JwtToken.getToken(uid,uName, JwtToken.defaultScope);
}
// 获取令牌
private static String getToken(Long uid,String uName, Integer scope) {
Algorithm algorithm = Algorithm.HMAC256(JwtToken.jwtKey);
Map<String,Date> map = JwtToken.calculateExpiredIssues();
/**
* withClaim() 写入自定义数据
* withExpiresAt() 设置过期时间
* withIssuedAt() 设置当前时间
* sign() 签名算法
*/
return JWT.create()
.withClaim("uid", uid) // payload 写入自定义数据
.withClaim("scope"