jwt介绍
1. JWT是什么
JSON Web Token (JWT),它是目前最流行的跨域身份验证解决方案
2. 为什么使用JWT
JWT的精髓在于:“去中心化”,数据是保存在客户端的。
解释:
我们知道有的界面用户是无法直接访问要登录或者获取权限之后才能访问 而这个数据一般是存储在服务器当中的所以我们假设有一万十万个用户都登录了或者还是更多的人都登录了那么对服务器的内存压力是很大的所以对服务器会造成较大的压力
而jwt则是将这个数据数据是保存在客户端的。
3. JWT的工作原理
-
是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户,示例如下:
{“UserName”: “Chongchong”,“Role”: “Admin”,“Expire”: “2018-08-08 20:15:56”} -
之后,当用户与服务器通信时,客户在请求中发回JSON对象
-
为了防止用户篡改数据,服务器将在生成对象时添加签名,并对发回的数据进行验证
解释:
在前端向后台发送请求之后后端会生成一个jwt令牌放到响应之中由前端获取到
再次访问后端发送请求时就会带着刚刚后端响应回来的请求前往后端从而进行验证
而每次响应的数据都会带着一个jwt令牌供我们下一次取请求后台所使用
所以就算我们登录之后再打开一个新的页面复制网址也无法获取数据
因为没有jwt令牌
4. JWT组成
一个JWT实际上就是一个字符串,它由三部分组成:头部(Header)、载荷(Payload)与签名(signature)
JWT结构原理图:见资料“JWT的数据结构.jpg”
JWT实际结构:eyJhbGciOiJIUzI1NiJ9.
eyJzdWIiOiJ7fSIsImlzcyI6InpraW5nIiwiZXhwIjoxNTYyODUwMjM3LCJpYXQiOjE1NjI4NDg0MzcsImp0aSI6ImM5OWEyMzRmMDc4NzQyZWE4YjlmYThlYmYzY2VhNjBlIiwidXNlcm5hbWUiOiJ6c3MifQ.
WUfqhFTeGzUZCpCfz5eeEpBXBZ8-lYg1htp-t7wD3I4
它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。
写成一行,就是下面的样子:Header.Payload.Signature
jwt使用
首先配置web.xml
jwtFilter com.zking.vue.util.JwtFilter jwtFilter /*JwtFilter
package com.zking.vue.util;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import io.jsonwebtoken.Claims;
/**
* * JWT验证过滤器,配置顺序 :CorsFilte-->JwtFilter-->struts2中央控制器
*
* @author Administrator
*
*/
public class JwtFilter implements Filter {
// 排除的URL,一般为登陆的URL(请改成自己登陆的URL)
private static String EXCLUDE = "^/vue/userAction_login\\.action?.*$";
private static Pattern PATTERN = Pattern.compile(EXCLUDE);
private boolean OFF = false;// true关闭jwt令牌验证功能
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String path = req.getServletPath();
if (OFF || isExcludeUrl(path)) {// 登陆直接放行
chain.doFilter(request, response);
return;
}
// 从客户端请求头中获得令牌并验证
String jwt = req.getHeader(JwtUtils.JWT_HEADER_KEY);
Claims claims = this.validateJwtToken(jwt);
if (null == claims) {
// resp.setCharacterEncoding("UTF-8");
resp.sendError(403, "JWT令牌已过期或已失效");
return;
} else {
String newJwt = JwtUtils.copyJwt(jwt, JwtUtils.JWT_WEB_TTL);
resp.setHeader(JwtUtils.JWT_HEADER_KEY, newJwt);
chain.doFilter(request, response);
}
}
/**
* 验证jwt令牌,验证通过返回声明(包括公有和私有),返回null则表示验证失败
*/
private Claims validateJwtToken(String jwt) {
Claims claims = null;
try {
if (null != jwt) {
claims = JwtUtils.parseJwt(jwt);
}
} catch (Exception e) {
e.printStackTrace();
}
return claims;
}
/**
* 是否为排除的URL
*
* @param path
* @return
*/
private boolean isExcludeUrl(String path) {
Matcher matcher = PATTERN.matcher(path);
return matcher.matches();
}
}
userAction
package com.zking.vue.web;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.opensymphony.xwork2.ModelDriven;
import com.zking.base.web.BaseAction;
import com.zking.vue.biz.UserBiz;
import com.zking.vue.entity.User;
import com.zking.vue.util.JsonData;
import com.zking.vue.util.JwtUtils;
import com.zking.vue.util.PageBean;
import com.zking.vue.util.ResponseUtil;
import com.zking.vue.util.StringUtils;
public class UserAction extends BaseAction implements ModelDriven<User>{
private UserBiz userBiz;
private User user = new User();
public UserBiz getUserBiz() {
return userBiz;
}
public void setUserBiz(UserBiz userBiz) {
this.userBiz = userBiz;
}
public String login() {
ObjectMapper om = new ObjectMapper();
JsonData jsonData = null;
try {
if(StringUtils.isBlank(user.getUname()) || StringUtils.isBlank(user.getPwd())) {
jsonData = new JsonData(0, "用户或者密码为空", user);
}else {
User u = this.userBiz.login(user);
Map<String, Object> claims = new HashMap<String, Object>();
claims.put("uname",user.getUname());
claims.put("pwd", user.getPwd());
String jwt = JwtUtils.createJwt(claims, JwtUtils.JWT_WEB_TTL);
response.setHeader(JwtUtils.JWT_HEADER_KEY, jwt);
jsonData = new JsonData(1, "登录成功", u);
}
} catch (Exception e) {
e.printStackTrace();
jsonData = new JsonData(0, "用户或者密码错误", user);
}finally {
try {
ResponseUtil.write(response, om.writeValueAsString(jsonData));
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
public String getAsyncData() {
ObjectMapper om = new ObjectMapper();
try {
Thread.sleep(6000);
ResponseUtil.write(response, om.writeValueAsString("http://www.javaxl.com"));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public User getModel() {
return user;
}
}
前端
mjx_spa/src/api/http.js
axios.interceptors.response.use(function(response) {
debugger;
var jwt = response.headers['jwt'];
if(jwt){
window.vm.$store.commit('setJwt',{jwt:jwt});
}
return response;
}, function(error) {
return Promise.reject(error);
})
定义一个jwt
在state.js里面定义
Mutations.js定义修改方法
setJwt:(state,payload)=>{
state.jwt=payload.jwt;
},
export default{
setResturantName:(state,payload)=>{
state.resturantName=payload.resturantName;
},
setJwt:(state,payload)=>{
state.jwt=payload.jwt;
},
doAjax:(state,payload)=>{
// 需求:想在当前的文件中与后台服务器做数据交互
let _this=payload._this;
let url = _this.axios.urls.SYSTEM_MENU_TREE;
// 箭头函数解决了this 指针污染的问题
_this.axios.post(url, {}).then((resp) => {
console.log(resp);
_this.menus=resp.data.result;
}).catch(function(error) {
console.log(error);
});
_this.$root.Bus.$on("collapsed-aside",(v)=>{
_this.collapsed=v;
});
}
}
Getters.js定义获取方法
getJwt:(state)=>{
return state.jwt;
}
http.js
// 请求拦截器
axios.interceptors.request.use(function(config) {
var jwt = window.vm.$store.getters.getJwt;
config.headers['jwt'] = jwt;
return config;
}, function(error) {
return Promise.reject(error);
});
// 响应拦截器
axios.interceptors.response.use(function(response) {
debugger;
var jwt = response.headers['jwt'];
if(jwt){
window.vm.$store.commit('setJwt',{jwt:jwt});
}
return response;
}, function(error) {
return Promise.reject(error);
});