整合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=jwt
spring.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=1234
mybatis.type-aliases-package=com.zuhao.springbootjwt.entity
mybatis.mapper-locations=classpath:com/zuhao/springbootjwt/mapper/*.xml
logging.level.com.zuhao.springbootjwt.dao=debug
JWT拦截器
interceptor包下新建拦截器
@Component
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
//目标资源方法执行前执行。 返回true:放行 返回false:不放行
@Override
public 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;
}
//==========下面与登录无关,不用写==============
//目标资源方法执行后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle ... ");
}
//视图渲染完毕后执行,最后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion .... ");
}
}
config包下添加拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//定义拦截对象
registry.addInterceptor(loginCheckInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(
"/users/login",
"/users/login/**",
"/swagger-ui/",
"/swagger-ui/**",
"/swagger-resources",
"/swagger-resources/**",
"/v3/**",
"/users/hello"
);
}
}