一、JWT简介:
JWT :json web token
官网:jwt.io
jwt的结构:
二、生成jwt
①添加依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
②生成token
String token = builder.setSubject(u.getTel())//设置主题,(就是token中携带的数据)
.setIssuedAt(new Date())//设置token生成的时间
.setId(u.getTel())//设置用户的手机号为token id
.setClaims(map)//map中可以存放用户的角色权限等信息
.setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000))//设置token的过期时间
.signWith(SignatureAlgorithm.HS256, "dalaolao")//设置加密方式和加密的密码
.compact();//生成
③解析token
//验证token
JwtParser parser = Jwts.parser();
parser.setSigningKey("dalaolao");//解析token时的SigningKey必须和设置token时的密码一致
try {
//如果token正确(密码正确,时间有效)则正常执行,否则抛出异常
Jws<Claims> claimsJws = parser.parseClaimsJws(token);
Claims body = claimsJws.getBody();//获取token中的用户数据
String subject = body.getSubject();//获取生成token时设置的subject
Object key1 = body.get("key1");//获取生成token时存储的Claims的map中存储的值
}catch (Exception e){
r.setMsg("登陆过期");
}
三、拦截器校验token
①创建拦截器
package com.qf.Interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.vo.ReturnCode;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
if (token == null) {
//提示请先登录
ReturnCode returnCode = new ReturnCode(1, "请先登录", null, null);
doResponse(response,returnCode);
return false;
} else {
try {
JwtParser parser = Jwts.parser();
parser.setSigningKey("dalaolao");
parser.parseClaimsJws(token);
return true;
} catch (Exception e) {
ReturnCode returnCode = new ReturnCode(1, "token无效", null, null);
doResponse(response,returnCode);
return false;
}
}
}
public void doResponse(HttpServletResponse response,ReturnCode returnCode) throws IOException {
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
String s = new ObjectMapper().writeValueAsString(returnCode);
writer.print(s);
writer.flush();
writer.close();
}
}
②配置拦截器
package com.qf.config;
import com.qf.Interceptor.TokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Resource
private TokenInterceptor tokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/users/testing")//设置需要拦截的路径
.excludePathPatterns("/news/**");//设置忽略拦截的路径
}
}
③请求头传递token
前端但凡访问受限资源,都必须携带token发送请求; token可以通过请求行(params)、请求头(header)以及请求体(data)传递,但是习惯性使用header传递
前端axios中header传值
axios({
method:'post',
url:'/api/users/testing',
headers:{token:CookieUtil.getCookieValue("token")},
}).then((res)=>{
console.log(res.data)
})
以下两部均在拦截器中处理
后端处理OPTIONS预检
请求
String method = request.getMethod();
if("OPTIONS".equalsIgnoreCase(method)){
return true;
}
后端接受请求同中的参数
String token = request.getHeader("token");
request.getMethod();
if(“OPTIONS”.equalsIgnoreCase(method)){
return true;
}
### 后端接受请求同中的参数
String token = request.getHeader("token");