- 所需依赖java-jwt与jjwt
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.15.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
- 在登录接口的业务层生成token
JwtBuilder builder = Jwts.builder();
HashMap<String, Object> map = new HashMap<>();
map.put("key1","value1");//可以使用map存储用户角色权限信息
String token = builder.setSubject(username)
.setIssuedAt(new Date())//设置token的生成时间
.setId(users.getUserId() + "")//设置用户id为token的id
.setClaims(map)//map中可以存放用户的角色权限信息
.setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000))//设置token的过期使时间
.signWith(SignatureAlgorithm.HS256, "yongxin")//设置加密方式和加密密码
.compact();
- 前端登录页面拿到token并将其存储在cookie中
//如果登录成功,把token存储到cookie中
setCookieValue("token",res.data.msg);
//这里把cookie的操作封装在一个js文件中
- 前端访问受限页面时间向后端请求在headers中携带token
前端但凡访问受限资源,都必须携带token发送请求,token可以通过请求行(params),请求头(header)以及请求体(data)传递,但是习惯性使用请求头(header)传递
created:function(){
this.token = getCookieValue("token");
axios({
method:"get",
url:baseUrl+"/shoppingCart/list",
headers:{
token:this.token
}
}).then(function(res){
//判断是否合法,合法则渲染页面
})
}
- 后端在拦截器中验证前端请求携带的token
注意:当前端发送的请求携带自定义请求头时,浏览器的预检机制会发送一次预检请求(mehtod=“options”),后端响应预检请求,之后前端才会发送真正携带数据的请求。因此我们要在拦截器中加以判断。
@Component
public class CheckTokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//放行预检请求
String method = request.getMethod();
if ("OPTIONS".equalsIgnoreCase(method)){
return true;
}
String token = request.getHeader("token");
if (token ==null){
ResultVO resultVO = new ResultVO(1001, "请先登录", null);
doResponse(response,resultVO);
}else {
//验证token
JwtParser parser = Jwts.parser();
parser.setSigningKey("yongxin");//解析token的SigningKey必须与生成token的密码一致
try {
Jws<Claims> claimsJws = parser.parseClaimsJws(token);
Claims body = claimsJws.getBody();//获取token中的用户数据
String subject = body.getSubject();
String v1 = body.get("key1", String.class);
ResultVO resultVO = new ResultVO(1000, "success", null);
doResponse(response,resultVO);
} catch (UnsupportedJwtException e){
ResultVO resultVO = new ResultVO(1001, "登录过期,请重新登录!", null);
doResponse(response,resultVO);
} catch (ExpiredJwtException e){
ResultVO resultVO = new ResultVO(1001, "token不合法,请自重!", null);
doResponse(response,resultVO);
} catch (Exception e){
ResultVO resultVO = new ResultVO(1001, "请重新登录!", null);
doResponse(response,resultVO);
}
}
return false;
}
private void doResponse(HttpServletResponse response, ResultVO resultVO) throws IOException {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
String s = new ObjectMapper().writeValueAsString(resultVO);
writer.println(s);
writer.flush();
writer.close();
}
}
注册拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private CheckTokenInterceptor checkTokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(checkTokenInterceptor)
.addPathPatterns("/shoppingCart/**");//需要拦截的受限资源请求
/*.excludePathPatterns("/users/**");*/
}
}