秦皇岛攻略:基于OAuth2.0的token无感知刷新

admin 2个月前 (10-10) 科技 78 2

  现在手头的vue项目关于权限一块有一个需求,实在架构师很早就要求我做了,然则由于这个紧要水平不是很高,最近邻近项目上线,我才想起,于是赶快补上这个功效。这个项目是基于OAuth2.0认证,需要在每个请求的头部携带access_token,若是这个access_token过时,需要行使已有的refresh _token去重新获取一个access_token,若是连这个refresh_token也过时了,那就是真正的过时了,需要退出登录页面。refresh_token在获取新的access_token的时刻需要让用户无感知,也叫无痛刷新。

  这里的代码实现肯定是要在axios拦截器里写的,然则是在请求拦截器里写照样在响应拦截器里写照样有区别的:

  1.写在请求拦截器里:每次请求之前都市先请求一个checkToken的接口,来确认这个access_token是否过时,若是没有过时,直接就提议原本的请求,若是过时,行使已有的refresh _token去重新获取一个access_token之后,再提议原本的请求。然则这样写有个瑕玷,就是每次请求之前都要分外请求一次checkToken的接口,若是网速欠好,会给用户造成欠好的体验,而且对服务器造成了性能上的虚耗。

  2.写在响应拦截器里:直到access_token过时,返回401未授权,才行使已有的refresh _token去重新获取一个access_token。

  最后我和后端讨论了下,最后采用了第二种方式,把checkToken放在后端,前端无感知刷新写在响应拦截器里。

这里写的一个响应拦截器:

import axios from 'axios'

//建立一个axios实例
const service = axios.create({
  timeout: 5000, // 请求超时时间
  withCredentials:true //示意跨域请求时是否需要使用凭证. 默以为false
})
var loading;//遮罩层

// 响应拦截器
service.interceptors.response.use( response => { //do what you like }, error => { loading.close(); if (error && error.response) { switch (error.response.status) { case 400: error.message = '请求错误' break case 401: return doRequest(error); case 403: error.message = '拒绝接见' break case 404: error.message = `请求地址失足: ${error.response.config.url}` break case 408: error.message = '请求超时' break case 500: error.message = '服务器内部错误' break case 501: error.message = '服务未实现' break case 502: error.message = '网关错误' break case 503: error.message = '服务不可用' break case 504: error.message = '网关超时' break case 505: error.message = 'HTTP版本不受支持' break default: break } } errorLog(error) return Promise.reject(error) } )

  export default service
 

  可以看到在响应拦截器的错误回调函数里401值的时刻调用了一个方式doRequest();

async function doRequest (error) {
  try {
    const data = await getNewToken();
    var token=data.data.token_type+' '+data.data.access_token;
    sessionStorage.setItem('RequestToken',token);
    const res = await service.request(error.config)
    return res;
  } catch(err) {
    Message({
      message: '登录会话已过时,请重新登录',
      type: 'error',
      duration: 5 * 1000
    })
    sessionStorage.clear();
    router.replace({
      path:"/login"
    });
    return err;
  }
}

  这里的重点这些请求必须是同步的,同步的,同步的,主要的事情说三遍,而axios默认是异步的,以是你要么使用ES6的async/await语句,要么使用then回调函数,必须保持是同步的。而getNewToken()则是行使refresh_token重新获取access_token方式。算了,一并贴出,仅作参考。

import qs from 'qs'

async function getNewToken() {
  var refreshToken=sessionStorage.getItem('refreshToken');
  return await axios({
    url: '/OAuth/oauth/token',
      method: 'post',
      headers: {
        'Authorization': 'Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
        'Content-Type':'application/x-www-form-urlencoded'
      },
    data:qs.stringify({
      grant_type:'refresh_token',
      refresh_token : refreshToken
    })
  })
}

  下面看效果。为了效果,这里设置了access_token有用时间为5s,refresh _token有用时间为10s。动图是这样的:

  一步一步分解下,登录的时刻,获取到access_token和refresh _token。然后带着access_token:f0a3******cb64去接见menuQuery接口是可以正常请求的。

   然则之后,我等了跨越5s后(不跨越10s,这个时刻access_token已过时,refresh _token未过时)发了一个对0304接口的请求,这个时刻返回401未授权,说明access_token:f0a3******cb64已过时。

   这时行使refresh_token重新获取access_token。

  可以看到返回了一个新的access_token:8332******1c8a,于是带着这个新的access_token重新提议对0304接口的请求,这个时刻就可以返回所需要的数据。

 

 

  之后再等跨越5s,这个时刻access_token过时了,refresh _token也过时了。动图是这样的:

 

   这时的请求返回的是400,而不是401了,这说明refresh _token:826b******17d1过时了。这个时刻就该退出登录界面,重新登录了。

   最后,放一个总的效果图:

,

Sunbet 申博

Sunbet 申博www.sunbet88.us是Sunbet指定的Sunbet官网,Sunbet提供Sunbet(Sunbet)、Sunbet、申博代理合作等业务。

Sunbet声明:该文看法仅代表作者自己,与本平台无关。转载请注明:秦皇岛攻略:基于OAuth2.0的token无感知刷新

网友评论

  • (*)

最新评论

标签列表

    文章归档

      站点信息

      • 文章总数:664
      • 页面总数:0
      • 分类总数:8
      • 标签总数:1145
      • 评论总数:250
      • 浏览总数:13424