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(路由) 进入指定路由
})
复制代码

举例:从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 执行时机

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

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

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)
复制代码


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


登录后会直接返回setting页面,该处理就算完成
3 请求拦截 (问题2:401)
3.1 理解token过期
登录成功后获得的token,在一定时间后就会失效,当这个时候,你再去发请求就会失效报错,而refresh_token可以在token过期后,重新请求token值,refresh_token也有有效期,可是这个有效期比较长
3.2 响应拦截器
axios提供了响应拦截器功能,所有后端回来的响应都会集中进入响应拦截器中,可以使用相应拦截器来查看token是否过期然后重新请求token

响应拦截器
// 添加响应拦截器
instance1.interceptors.response.use(function (response) {
return response
}, async function (error) {
// 如果发生了错误,判断是否是401
console.dir(error)
// 开始处理
return Promise.reject(error)
})
复制代码
3.3 解决实例(token失效时去关注文章或者取消关注文章)
整体思路

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存在



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



4 后记























![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)