整合JWT
令牌组成
- 1.标头(Header)
- 2.有效载荷(Payload)
- 3.签名(Signature)
因此,JWT通常如下所示:xxxxx.yyyyy.zzzzz
Header.Payload.Signature
jwt组成
Header
标头通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法,例如HMAC SHA256或RSA。它会使用 Base64 编码组成 JWT 结构的第一部分。
- 注意:Base64是一种编码,也就是说,它是可以被翻译回原来的样子来的。它并不是一种加密过程。
{"alg": "HS256","typ": "JWT"
}
Payload
不要在这里放密码;反编译Base64即可解码;
- 令牌的第二部分是有效负载,其中包含声明。声明是有关实体
- (通常是用户)和其他数据的声明。同样的,它会使用 Base64 编码组成 JWT 结构的第二部分
{"username": "xzxadmin","datetime": "2023-05-01 11:11:11","role": "admin"
}
Signature
- 前面两部分都是使用 Base64 进行编码的,即前端可以解开知道里面的信息。Signature 需要使用编码后的 header 和 payload以及我们提供的一个密钥,然后使用 header 中指定的签名算法(HS256)进行签名。签名的作用是保证 JWT 没有被篡改过
- 如:
HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload),secret);
整合JWT
<!--引入jwt-->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version>
</dependency>
JWT帮助类
public class JwtUtils {//常量public static final long time = 1000 * 60 * 60 * 24;//token过期时间public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";//秘钥//生成token字符串的方法public static String getJwtToken(String username, String role){String JwtToken = Jwts.builder()//头部.setHeaderParam("typ","JWT").setHeaderParam("alg","HS256")//载荷.claim("username",username).claim("role",role).setSubject("jwt-user")//token过期时间:1小时.setExpiration(new Date(System.currentTimeMillis()+time )).setId(UUID.randomUUID().toString())//id字段//签名.signWith(SignatureAlgorithm.HS256,APP_SECRET)//签名加密算法和//连接字符串(.);.compact();return JwtToken;}/*** 判断token是否存在与有效* @param jwtToken* @return*/public static boolean checkToken(String jwtToken) {if(StringUtils.isEmpty(jwtToken)) return false;try {Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** 判断token是否存在与有效* @param request* @return*/public static boolean checkToken(HttpServletRequest request) {try {String jwtToken = request.getHeader("token");if(StringUtils.isEmpty(jwtToken)) return false;Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** 根据token获取会员id* @param request* @return*/public static String getMemberIdByJwtToken(HttpServletRequest request) {String jwtToken = request.getHeader("token");if(StringUtils.isEmpty(jwtToken)) return "";Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);Claims claims = claimsJws.getBody();return (String)claims.get("id");}
}
整合JWT
导入依赖
<!--引入jwt-->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version>
</dependency><!--引入mybatis-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.3</version>
</dependency><!--引入lombok-->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version>
</dependency><!--引入druid-->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.19</version>
</dependency><!--引入mysql-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency>
配置文件
server.port=8989
spring.application.name=jwtspring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/jwt?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC&useSSL=false
spring.datasource.username=root
spring.datasource.password=1234mybatis.type-aliases-package=com.zuhao.springbootjwt.entity
mybatis.mapper-locations=classpath:com/zuhao/springbootjwt/mapper/*.xmllogging.level.com.zuhao.springbootjwt.dao=debug
JWT拦截器
interceptor包下新建拦截器
@Component
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {//目标资源方法执行前执行。 返回true:放行 返回false:不放行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1,先获取请求头String token = request.getHeader("Authorization");System.out.println("token:"+token);response.setContentType("application/json;charset = UTF-8");ObjectMapper mapper = new ObjectMapper();//2,判断请求头是否存在if (token == null || "".equals(token)){//请求头不存在或者请求头为空log.info("...token不存在");response.getWriter().write("result:缺少token");return false;}else{try {boolean isJwt = JwtUtils.checkToken(token);//解析不出错就是格式有效;/*从redis中查询token*///时间有效,通过;时间无效,过期;} catch (Exception e) {log.info("请求头不正确!!");response.getWriter().write("result:token错误:");return false;}}return true;}//==========下面与登录无关,不用写==============//目标资源方法执行后执行@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle ... ");}//视图渲染完毕后执行,最后执行@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion .... ");}
}
config包下添加拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//定义拦截对象registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/users/login","/users/login/**","/swagger-ui/","/swagger-ui/**","/swagger-resources","/swagger-resources/**","/v3/**","/users/hello");}
}