token权限处理

token的权限处理问题(部分)

1 关于token的权限问题

问题1

如果你没有登录去访问一些敏感页面,例如更改个人资料页面,就阻止访问并提醒登录

问题2

401错误

(1)没有登录的用户使用一些需要权限才能使用的操作,比如关注作者评论或者点赞等操作,就会报401错误

(2)token过期,使用refresh_token重新获取新的token

2 路由守卫 (问题1)

2.1 路由守卫

全局守卫

router对象的一个属性,本质上是一个函数,只要切换路由,它就会被调用,可以在这里去查看用户是否登录(是否有token)

// 全局守卫
router.beforeEach(function (to, from, next) {
  console.log('路由变化了', to, from, next)
  // to表示当前路由变化,你进入哪个路由
  // from表示你要离开哪个路由
  // next是一个函数,必须调用来结束当前动作的处置
  next() // 正常放行
})

router.afterEach(function (to, from) {
  console.log('路由变化了', to, from)
  next()
  // next(false)
  // next(路由) 进入指定路由
})
复制代码

image.png
举例:从home页面到setting页面,这时候还没有设置敏感页面,成功跳转

组件守卫

组件得是路由级别的组件

const Foo = {
  template: `...`,
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}
复制代码

路由独享守卫

在路由配置上直接定义beforeEnter守卫

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
复制代码

2.2 执行时机

image.png

2.3 解决实例 (访问个人中心,验证是否登录)

整体思路

image.png

代码实现

可以新建一个auth文件单独来写全局守卫,注意:要导入main.js

image.png

import store from '@/store/index.js'
import router from '@/router/index.js'

const interceptPage = ['/setting'] // 设置敏感页面,举例为个人中心

router.beforeEach(function (to, from, next) {
  console.log('路由变化了', to, from)
  const token = store.state.tokenInfo.token // 从vuex里面取出保存的token
  // 校验是否有token,并且校验要访问的页面是否为敏感页面
  if (!token && interceptPage.includes(to.path)) { 
  // 没有token并且访问的是敏感页面,显示没有权限并且跳转到登录页面
    console.log('没有权限,不能访问')
    // 返回登录页面登录,并且保存下登录前要去的地址,在登陆后直接跳转到那个页面
    // encodeURIComponent的作用:对URL中的&=/等特殊符号进行编码
    next('/login?backto=' + encodeURIComponent(to.fullPath))
  } else if (token && to.path === '/login') {
    // 有token的情况,如果跳转登录页,直接返回首页
    console.log('您已经登录了')
    next('/')
  } else {
    // 不管有没有token,也没有访问敏感页面,可以随意访问
    next()
  }
})

export default router
复制代码

login中也要改进跳转的地址

const backto = this.$route.query.backto || '/'
this.$router.push(backto)
复制代码

image.png
image.png

测试效果

在没有token的情况,直接在地址栏中访问setting将无法访问,而会跳回login页面

image.png

image.png
登录后会直接返回setting页面,该处理就算完成

3 请求拦截 (问题2:401)

3.1 理解token过期

登录成功后获得的token,在一定时间后就会失效,当这个时候,你再去发请求就会失效报错,而refresh_token可以在token过期后,重新请求token值,refresh_token也有有效期,可是这个有效期比较长

3.2 响应拦截器

axios提供了响应拦截器功能,所有后端回来的响应都会集中进入响应拦截器中,可以使用相应拦截器来查看token是否过期然后重新请求token

image.png
响应拦截器

// 添加响应拦截器
instance1.interceptors.response.use(function (response) {
  return response
}, async function (error) {
  // 如果发生了错误,判断是否是401
  console.dir(error)
  // 开始处理
  return Promise.reject(error)
})
复制代码

3.3 解决实例(token失效时去关注文章或者取消关注文章)

整体思路

image.png
1.用户发出请求A,如果token过期或者没有token,出现401错误,就去使用refresh_token重新获取token

2.校验有没有refresh_token,如果没有就返回登录,如果有就重新请求token

3.重新请求到token后更新vuex,然后在重新发送请求A,如果token更新失败,也返回重新登录

4.正常响应

代码实现

utils/request.js中实现

+import store from '@/store/index.js'
+import router from '@/router/auth.js'
// 添加响应拦截器
request.interceptors.response.use(function (response) {
  return response
}, async function (error) {
  console.dir(error)
  // 如果发生了错误,判断是否是401
  if (error.response.status === 401) {
    // 开始处理
    console.log('发生错误' + error.response.status)
    const refreshToken = store.state.tokenInfo.refresh_token
    // 判断是否有refreshToken
    if (refreshToken) {
      try {
        // 使用refreshT_token重新获取token
        const res = await axios({
          url: '后端接口地址',
          method: '请求方式',
          headers: {
            Authorization: `Bearer ${refreshToken}`
          }
        })
        console.log(res)
        // 在store中保存新的token
        store.commit('setTokenInfo', {
          refresh_token: refreshToken,
          token: res.data.data.token
        })
        return request(error.config)
      } catch (error) {
        // 如果带有token,即使是过期的token,可是全局守卫会认为你有token已经登录,所以会直接跳转到首页,所以这个时候要把已经失效的token清空
        store.commit('setTokenInfo', {})
        const backtoURL = encodeURIComponent(router.currentRoute.fullPath)
        router.push('/login?backto=' + backtoURL)
        return Promise.reject(error)
      }
    } else {
      // 没有refresh_token返回登录重新获取
      store.commit('setTokenInfo', {})
      const backtoURL = encodeURIComponent(router.currentRoute.fullPath)
      console.log(backtoURL)
      router.push('/login?backto=' + backtoURL)
      return Promise.reject(error)
    }
  } else {
    return Promise.reject(error)
  }
})
复制代码

vuex中的mutations代码

mutations: {
  ...
    // 重新保存token
    setTokenInfo (state, newTokenInfo) {
      state.tokenInfo = newTokenInfo
      setToken(newTokenInfo)
    }
  }
复制代码

测试效果

第一种情况:token失效,refresh_token存在
image.png

image.png

image.png
第二种情况:token和refresh_token都报错

image.png

image.png

image.png

4 后记

image.png

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享