运城公司网站建设,新手小白怎样运营1688店铺,wordpress 云备份数据库,宝塔做网站安全吗前文介绍过jwt的一般使用场景#xff0c;用户登录成功后获得jwt#xff0c;其中包含用户相关信息#xff0c;主要是在前端要用到的属性#xff08;比如姓名、应用角色[这个前端后都用得着]等#xff09;、在后端要用到的属性#xff08;比如登录IP、终端唯一标识#xf…前文介绍过jwt的一般使用场景用户登录成功后获得jwt其中包含用户相关信息主要是在前端要用到的属性比如姓名、应用角色[这个前端后都用得着]等、在后端要用到的属性比如登录IP、终端唯一标识、token过期时间这个前后端都可以检查之后调用后端服务都会在header里带上jwt具体就是Authorization属性的值设置为’Bearer ’ jwt。这样后端收到请求后会对jwt进行验签和解析如果签名正确且在有效期内则认可jwt解析出来的用户身份进行相关后续处理否则跳转登录界面重新登录。 出于安全考虑再加上用户身份权限也不是一成不变的所以一般token有效期不应设置过长比如一个小时其实不论多长时间总会有超期时间这时候用户访问时会跳转到登录界面要求重新登录这样的体验是不太好的所以一般情况下登录成功后可以提供两个token给前端一个是access_token也就是前面介绍的通常意义上的jwt而另一个是refresh_token它的有效期比access_token的要长一些用户在access_token过期且access_token未过期情况下可为前端重新申请access_token其实也可以同时更新refresh_token 我们可以将refresh_token放在access_token的属性中这样每次access_token传到后端时refresh_token也自然一起传了过来在后端主动推送token的场景下要求前端每次请求都传两个token的。前端主动申请刷新token的场景下refresh_token就没有必要每次传只要在刷新时传就可以了也就没有必要将refresh_token放在access_token的属性中。 其实有两种方式来执行token的更新一种是利用了后端主动访问前端的SSE或者websocket方式后端解析请求发现access_token过期且refresh_token未过期可以主动从SSE或websocket通道连接前端推送新的access_token和refresh_token到前端前端收到token更新后存入本地存储并在每次发起后端请求时放在header相关属性中一并发出。不过这种方式由于要维护前端通信通道有违http服务无状态的初衷虽然可以实现不过不推荐。 另外一种是在前端axios里配置拦截器可以配置请求拦截或者响应拦截。区别如下请求拦截的话每次发起请求前检查access_token是否超期如果没有直接发起原请求否则检查refresh_token是否超期如果超期则跳转登录界面还在有效期的话可以发起刷新token的调用更新token。返回后写入token到本地然后放在header里发起原请求另外由于很难要求前后端时间严格同步所以建议在access_token到期前一段时间内比如一分钟就请求刷新。响应拦截的话请求后根据服务器响应再做后续处理如果响应正常则原响应返回如果提示token超期的话要执行刷新token返回后写入token到本地然后放在header里发起原请求。两种拦截器效果区别不大不过按javascript风格——先操作再处理error——的话是倾向于响应拦截器的。 这里还有一个小问题就是在本地存储的token过期而新的token尚未返回写入本地存储时可能发起了多个请求如果后端每次都新生成token就没有必要了后端可以考虑维护一个列表存有新生成的token、有效期与前端ip或者唯一标识这样只要在列表中找到就不用重新生成直接分配即可。此时前端处理会比较简单会发起多次申请和写入不过写入的是同样的内容其实也没有啥不太好的影响主要是多次申请token和写回本地存储有些前后端的多余的不必要的开销。改进的方式是在前端设置一个变量来标识是否处于刷新token中这样第一个刷新会向后端提交申请而其余的返回token过期的申请或者新的请求申请要暂时挂起放入队列不提交等待这第一个刷新完成后队列里申请再激活提交。示例代码如下主要逻辑在响应拦截器里处理配置请求拦截器是为了处理刷新token期间的请求挂起并在刷新到token后恢复。
var inRefresh false;
var reqlist [];const instance axios.create();
instance.interceptors.request.use(config{if (!inRefresh) return config;return new Promise(resolve {reqlist.push(token{config.headers.Authorization Bearer token;resolve(config);})})
});instance.interceptors.response.use( response { return response }, error {if (error.response.status 401) {let config error.config;if (!inRefresh) {inRefresh true;axios.post(/app/refresh_token,{refresh_token:localStorage.getItem(refresh_token)}).then(res{let jwtres.data.access_token;config.defaults.headers.common[Authorization] Bearer jwt;localStorage.setItem(jwt, jwt);localStorage.setItem(refresh_token, res.data.refresh_token);reqlist.forEach((cb) cb(jwt));reqlist [];return instance(config);}).catch(err { return Promise.reject(err) }).finally(() { inRefresh false })}else {return new Promise(resolve {reqlist.push(token {config.headers.Authorization Bearer token;resolve(instance(config));})})}}else return Promise.reject(error)
})