JWT
JWT是什么
JWT的介绍
JWT全称位JSON Web Token,是当前企业主流的一种认证方式,本质是是一个JSON格式的字符串
官网
JWT的构成
JWT由三部分构成:Header(头)、Payload(有效载荷)、Signature(签名)
ps:JWT的Header和Payload是经过base64处理后生成的,签名的作用是校验数据是否被篡改
JWT的作用
JWT认证和session认证的区别
session流程图
JWT流程图
总结:
主要区别就是用户状态的保存的位置,session是保存在服务端的,而JWT是保存在客户端的
JWT如何做到防篡改
将 Token 和 时间戳 加上其他请求参数再用MD5或SHA-1算法(可根据情况加点盐)加密,加密后的数据就是本次请求的签名sign,服务端接收到请求后以同样的算法得到签名,并跟当前的签名进行比对,如果不一样,说明参数被更改过,直接返回错误标识。签名机制保证了数据不会被篡改
作用:
因为前后端分离开发,一般用于用户登录后,使用其他功能校验身份。
JWT的入门例子
思路:
1、导入依赖
Java中操作JWT有多种实现方式,其中比较常用的是 jjwt,源码地址
2、配置配置类.yml
jwt:
# 设置jwt签名加密时使用的秘钥
admin-secret-key: xxx
# 设置jwt过期时间
admin-ttl: 7200000
# 设置前端传递过来的令牌名称
admin-token-name: token
3、加载配置类的加载类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "reggie.jwt")
@Data
public class JwtProperties {
/**
* 生成jwt令牌相关配置
*/
private String adminSecretKey;
private long adminTtl;
private String adminTokenName;
4、封装工具类
作用:方便操作JWT
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
public class JwtUtil {
/**
* 生成jwt
* 使用Hs256算法, 私匙使用固定秘钥
*
* @param secretKey jwt秘钥
* @param ttlMillis jwt过期时间(毫秒)
* @param claims 设置的信息
* @return
*/
public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {
// 指定签名的时候使用的签名算法,也就是header那部分
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
// 生成JWT的时间
long expMillis = System.currentTimeMillis() + ttlMillis;
Date exp = new Date(expMillis);
// 设置jwt的body
JwtBuilder builder = Jwts.builder()
//设置主题数据
.setClaims(claims)
// 设置签名使用的签名算法和签名使用的秘钥
.signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))
// 设置过期时间
.setExpiration(exp);
return builder.compact();
}
/**
* Token解密
*
* @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个
* @param token 加密后的token
* @return
*/
public static Claims parseJWT(String secretKey, String token) {
// 得到DefaultJwtParser
Claims claims = Jwts.parser()
// 设置签名的秘钥
.setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))
// 设置需要解析的jwt
.parseClaimsJws(token).getBody();
return claims;
}
}
5、注册自定义拦截器
作用:使得每次访问都要拦截验证Token令牌
@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Autowired
private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
/**
* 注册自定义拦截器
* @param registry
*/
protected void addInterceptors(InterceptorRegistry registry) {
log.info("开始注册自定义拦截器:{}",jwtTokenAdminInterceptor);
registry.addInterceptor(jwtTokenAdminInterceptor)
.addPathPatterns("/admin/**")
//除了登录功能,进入其他功能都要拦截验证
.excludePathPatterns("/admin/employee/login");
}
6、jwt令牌校验的拦截器
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {
@Autowired
private JwtProperties jwtProperties;
/**
* 校验jwt
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("jwt校验...");
//判断当前拦截到的是Controller的方法还是其他资源
if(!(handler instanceof HandlerMethod)){
//当前拦截到的不是动态方法,直接放行
return true;
}
//获取当前被拦截的方法上是否存在IgnoreToken注解
HandlerMethod handlerMethod = (HandlerMethod)handler;
boolean hasMethodAnnotation = handlerMethod.hasMethodAnnotation(IgnoreToken.class);
if(hasMethodAnnotation){
return true;
}
//1、从请求头中获取令牌
String token = request.getHeader(jwtProperties.getAdminTokenName());
//2、校验令牌
try{
Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
BaseContext.setCurrentId(empId);
//3、通过,放行
return true;
}catch (Exception ex){
//4、不通过,响应401状态码
response.setStatus(401);
return false;
}
}
}