vue项目登录鉴权 + 动态路由

        一个系统有多个角色,不同角色登录后应该有不同的路由表,保证用户乱输url不会访问到正确的地址,而是跳转到404页面。这里用token进行鉴权主要是防止csrf攻击。

1、csrf攻击

        跨站脚本伪造,就是在登录安全网站之后诱导用户点击危险网站,那么危险网站就可以得到用户的cookie从而冒充用户身份对安全网站进行访问和一些违法操作。

那么关键点就在于:

  • 登录受信任站点 A,并在本地生成cookie;
  • 在不登出站点A(清除站点A的cookie)的情况下,访问恶意站点B。

所以防范的方法之一是用不能截取的token。

那这里用token进行验证,分为token存在和token不存在的情况

router.beforeEach((to, from, next) => {
  if (!getToken()) next({ name: 'Login' })
  else next()
})

2、在路由信息地meta中新增拥有当前权限的角色

routes: [
    {
        path: '/login',
        name: 'login',
        meta: {
            roles: ['admin', 'user']
        },
        component: () => import('../components/Login.vue')
    },
    {
        path: 'home',
        name: 'home',
        meta: {
            roles: ['admin']
        },
        component: () => import('../views/Home.vue')
    },
]

然后在router.beforeEach中控制路由是否展示

//假设有三种角色:admin 和 user 和 manager
//从后台获取的用户角色,一个用户可能有多个角色
const role = [admin, user]  //从localStorage中获取
//当进入一个页面是会触发导航守卫 router.beforeEach 事件
router.beforeEach((to, from, next) => {
    const auth = role.filter((item) => to.meta.roles.includes(item));  //两个数组有交集,就放行
    if (auth.length) {
        next() //放行
    } else {
        next({path:"/404"}) //跳到404页面
    }
})

问题:使用router.beforeEach时,发现刷新页面,不会触发router.beforeEach.

方案:将router绑定到new Vue的app上的顺序,需要在main.js的底部,也就是要先写router.beforeEach函数,再将router绑定到vue根实例上。

3、route.js中默认只有login和register的页面路由

        route.js中默认只有login和register的页面路由,其余路由都是通过vue-router的addRouter来添加的,需要注意的是,动态添加路由是在路由表中 push 路由,由于路由是按顺序匹配的,因此需要将诸如404页面这样的路由放在动态添加的最后。

// dynamicRoutes.js
// 将需要动态注册的路由提取到vuex中
const dynamicRoutes = [
    {
        path: '/manage',
        name: 'Manage',
        meta: {
            requireAuth: true
        },
        component: () => import('./views/Manage')
    },
    {
        path: '/userCenter',
        name: 'UserCenter',
        meta: {
            requireAuth: true
        },
        component: () => import('./views/UserCenter')
    }
]

登录后在路由跳转之前,调接口获取当前用户的角色的路由权限表。

将表数据存到sessionStorage的routers中,然后和上面要引入的dynamicRoutes做双向深度递归遍历,将有权限的路由筛选出来。

然后this.$router.addRoutes(筛选后的路由),然后再进行路由的跳转。

这样登录之后,正常的路由跳转是没有问题,但是一刷新就完蛋了,因为刷新后router.js就重新初始化了,动态的路由表不见了。这时候刚刚存储在sessionStorage的routers就起作用了,我本来打算将刷新后的动态路由添加放在根目录的created中,后来发现这样不行。于是就直接将这一层判断放到了main.js中。

// main.js
import dynamicRoutes from '../routes/dynamicRoutes.js';
import router from 'vue-router'
let localRoutes = sessionStorage.getItem('routers');
if (localRoutes) {
    const route =  dynamicRoutes.filter((item) => localRoutes.includes(item)) //多层级路由要递归遍历;
    router.addRoutes(route);
}

这样就实现了刷新页面也可以获取到sessionStorage里面的数据。这里的存储位置放在vuex中也可以,不过vuex也有刷新页面数据丢失的问题,原理同上。

4、鉴权和路由示例

import Vue from 'vue'
import $cookies from 'vue-cookies'
import VueRouter from 'vue-router'
import store from '../store'​
import staticRoute from './static-route.js'​​​
Vue.use(VueRouter)​​
const router = new VueRouter({
	mode: 'history',
	base: process.env.BASE_URL,
	routes: staticRoute //staticRoute为静态路由,不需动态添加
})​
let isToken = true
router.beforeEach(async (to, from, next) => {
	//定义isToken为true和vuex不为空时添加路由
	if (isToken && store.state.routers.routers.length != 0) {
		//从vuex中获取动态路由
		const accessRouteses = await store.state.routers.routers;
		//动态路由循环解析和添加
		accessRouteses.forEach(v => {
			v.children = routerChildren(v.children);
			v.component = routerCom(v.component);
			router.addRoute(v); //添加
		})
		isToken = false //将isToken赋为 false ,否则会一直循环,崩溃
		next({
			...to, // next({ ...to })的目的,是保证路由添加完了再进入页面 (可以理解为重进一次)
			replace: true, // 重进一次, 不保留重复历史
		})​
	} else {
		if (to.name == null) {
			next("/404")
		} else {
			if (to.meta.title) { //判断是否有标题
				document.title = to.meta.title //给相应页面添加标题
			}
			next()
		}​
	}​
})​
function routerCom(path) { //对路由的component解析
	return (resolve) => require([`@/views/${path}`], resolve);
}​
function routerChildren(children) { //对子路由的component解析
	children.forEach(v => {
		v.component = routerCom(v.component);
		if (v.children != undefined) {
			v.children = routerChildren(v.children)
		}
	})
	return children;
}​​
export default router​;

猜你喜欢

转载自blog.csdn.net/qq_24518001/article/details/127955020
今日推荐