Ventajas y desventajas
ventaja:
- La tabla de enrutamiento se mantiene en el front-end sin la ayuda del back-end
- La lógica es relativamente simple y fácil de usar.
- La autenticación front-end es más conveniente para sistemas con menos permisos
defecto:
- Cada vez que se modifica la página de permisos en la versión en línea, es necesario volver a empaquetar el proyecto.
- No apto para grandes proyectos.
- Si necesita agregar roles a la página y controlar las páginas a las que se puede acceder, no puede usar la autenticación de front-end.
Ideas específicas
1. El front-end define el enrutamiento estático y el enrutamiento dinámico. Al crear una instancia de vue, vue-router monta el enrutamiento estático (páginas que no requieren permisos como inicio de sesión) 2. Obtenga información del usuario al iniciar sesión, guárdela en vuex
y almacenar token
3. En el enrutamiento En el interceptor, use el token para obtener la función de usuario y use la función para obtener todas las rutas accesibles 4.
Llame a router.addrouters (store.state.addRouters) para agregar rutas accesibles
5. Borre la información del usuario al salir, roles claros y rutas claras
Paso 1: definir el enrutamiento estático y el enrutamiento dinámico en el front-end
enrutador/index.js
import Vue from "vue"
import VueRouter from "vue-router"
import Layout from "@/layout"
Vue.use(VueRouter)
// 解决重复点击路由报错的BUG
// 下面这段代码主要解决这个问题 :Uncaught (in promise) Error: Redirected when going from "/login" to "/index" via a navigation guard.
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch((err) => err)
}
// 定义好静态路由
export const constantRoutes = [
{
path: "/login",
name: "login",
component: () => import("../views/login"),
hidden: true,
},
]
// 定义动态路由,以及每个页面对应的roles(写在meta中,不写代表都可以访问)
export const asyncRoutes = [
{
id: 1,
name: "/",
path: "/",
component: Layout,
redirect: "/index",
hidden: false,
children: [
{
name: "index",
path: "/index",
meta: {
title: "index" },
component: () => import("@/views/index"),
},
],
},
{
id: 2,
name: "/form",
path: "/form",
component: Layout,
redirect: "/form/index",
hidden: false,
children: [
{
name: "/form/index",
path: "/form/index",
meta: {
title: "form" },
component: () => import("@/views/form"),
},
],
},
{
id: 3,
name: "/example",
path: "/example",
component: Layout,
redirect: "/example/tree",
meta: {
title: "example" },
hidden: false,
children: [
{
name: "/tree",
path: "/example/tree",
meta: {
title: "tree" },
component: () => import("@/views/tree"),
},
{
name: "/copy",
path: "/example/copy",
meta: {
title: "copy" },
component: () => import("@/views/tree/copy"),
},
],
},
{
id: 4,
name: "/table",
path: "/table",
component: Layout,
redirect: "/table/index",
hidden: false,
meta: {
roles: ["admin"] },
children: [
{
name: "/table/index",
path: "/table/index",
meta: {
title: "table", roles: ["admin"] },
component: () => import("@/views/table"),
},
],
},
{
id: 5,
name: "/admin",
path: "/admin",
component: Layout,
redirect: "/admin/index",
hidden: false,
meta: {
roles: ["admin"] },
children: [
{
name: "/admin/index",
path: "/admin/index",
meta: {
title: "admin", roles: ["admin"] },
component: () => import("@/views/admin"),
},
],
},
{
id: 6,
name: "/people",
path: "/people",
component: Layout,
redirect: "/people/index",
hidden: false,
meta: {
roles: ["admin", "common_user"] },
children: [
{
name: "/people/index",
path: "/people/index",
meta: {
title: "people", roles: ["admin", "common_user"] },
component: () => import("@/views/people"),
},
],
},
{
id: 7,
name: "/404",
path: "/404",
component: () => import("@/views/404"),
},
// 注意404页面要放到最后
{
path: "*", redirect: "/404", hidden: true },
]
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes: constantRoutes,
})
export default router
meta
Aquí usamos etiquetas para indicar los permisos a los que puede acceder la página modificada según el método recomendado oficialmente por vue-router . Por ejemplo, meta: { role: ['admin', 'super_editor'] } indica que solo los administradores y supereditores son elegibles para ingresar a esta página.
注意事项
: Una cosa a tener en cuenta aquí es que la página 404 debe cargarse al final. Si declara 404 junto con ConstantRoutes, todas las páginas posteriores se bloquearán en 404.
Paso 2: obtenga información del usuario al iniciar sesión, guárdela en vuex y almacene el token
iniciar sesión/index.vue
methods: {
login () {
this.$refs.userForm.validate((valid) => {
if (valid) {
// 模拟登录接口去请求用户数据
setTimeout(() => {
// 这里的res就是模拟后台返回的用户数据(不包含用户角色,一般角色是由单独的一个接口返回)
const res = dynamicUserData.filter((item) => item.username === this.user.username)[0]
console.log(res)
// 存储用户的信息及token到vuex,并做sessionStorage持久化处理
this.$store.commit('User/saveUserInfo', res)
Message({
type: 'success', message: "登录成功", showClose: true, duration: 3000 })
this.$router.push({
path: "/index" })
}, 1000)
} else return false
})
}
}
Adjunto: procesamiento de persistencia de vuex
import Vue from 'vue'
import Vuex from 'vuex'
import User from './modules/user'
import permission from './modules/permission'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
User,
permission,
},
plugins: [
createPersistedState({
storage: window.sessionStorage, // 可选sessionStorage localStorage
reducer(val) {
return {
User: val.User,
}
},
}),
],
})
Paso [34]: en el interceptor de rutas, use el token para obtener la función de usuario, use la función para obtener todas las rutas accesibles y llame a router.addrouters(store.state.addRouters) para agregar rutas accesibles
Lógica del enlace de enrutamiento:
是否为白名单页面
是: 直接进入
不是: 判断是否有token
无token:跳转到login登录页
有token: 判断用户是否有角色权限表
有权限表:直接进入
无权限表:调接口获取用户角色,并存储到vuex
根据返回的角色和路由表每个页面的需要的权限对比,生成可访问的路由表
使用router.addRouters()添加路由
Guardia de navegación de ruta:
import router from "./index"
import NProgress from "nprogress" // progress bar
import store from "@/store"
import menu from "@/mock/menu.js"
NProgress.configure({
showSpinner: false }) // NProgress Configuration
// 白名单页面直接进入
const whiteList = ["/login"]
router.beforeEach((to, from, next) => {
NProgress.start()
// 白名单页面,不管是否有token,是否登录都直接进入
if (whiteList.indexOf(to.path) !== -1) {
next()
return false
}
// 有token(代表了有用户信息,但是不确定有没有角色权限数组)
if (store.state.User.token) {
// 判断当前用户是否有角色权限数组, 是登录状态则一定有路由,直接放行,不是登录状态则去获取路由菜单登录
// 刷新时hasRoles会重置为false,重新去获取 用户的角色列表
const hasRoles = store.state.permission.roles && store.state.permission.roles.length > 0
if (!hasRoles) {
setTimeout(async () => {
const roles = menu.filter((item) => item.token === store.state.User.token)[0].roles
// 将该角色权限数组存储到vuex中
store.commit("permission/setRoles", roles)
// 根据返回的角色信息去过滤异步路由中该角色可访问的页面
const accessRoutes = await store.dispatch("permission/generateRoutes", roles)
// dynamically add accessible routes
router.addRoutes(accessRoutes)
// hack方法 router.addRoutes之后的next()可能会失效,因为可能next()的时候路由并没有完全add完成 next(to)解决
next({
...to, replace: true })
}, 500)
} else {
next() //当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的全面会自动进入404页面
}
} else {
next({
path: "/login" })
}
})
router.afterEach(() => {
// finish progress bar
NProgress.done()
})
Lo que se debe hacer en vuex es: filtrar las rutas dinámicas definidas a través de la matriz de permisos de rol (devuelta en segundo plano), filtrar las rutas que tiene el usuario y luego agregar las rutas filtradas a la parte posterior de la ruta estática para almacenar/permiso
. .js
import {
asyncRoutes, constantRoutes } from '@/router'
/**
* Filter asynchronous routing tables by recursion
* @param routes asyncRoutes
* @param roles
*/
export function filterAsyncRoutes(routes, roles) {
const res = []
routes.forEach(route => {
const tmp = {
...route }
if (hasPermission(roles, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
})
return res
}
function hasPermission(roles, route) {
console.log(roles)
console.log(route)
if (route.meta && route.meta.roles) {
console.log(roles.some(role => route.meta.roles.includes(role)))
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
}
const state = {
roles: [],
routes: [],
addRoutes: [],
}
const mutations = {
setRoles(state, val) {
state.roles = val
},
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
},
}
const actions = {
generateRoutes({
commit }, roles) {
return new Promise(resolve => {
let accessedRoutes
if (roles.includes('admin')) {
// admin直接添加所有权限
accessedRoutes = asyncRoutes || []
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
},
}
export default {
namespaced: true,
state,
mutations,
actions,
}
Paso 4: borre la información, los roles y las rutas del usuario al salir
methods: {
// 退出登录
handleLogout() {
window.localStorage.removeItem("token")
// 清除用户信息
this.$store.commit("User/removeUserInfo")
// 清除角色权限列表
this.$store.commit("permission/setRoles", [])
// 清除角色权限数组
this.$store.commit("permission/SET_ROUTES", [])
Message({
type: "success",
message: "退出登录",
showClose: true,
duration: 3000,
})
this.$router.push({
path: "/login" })
},
}
espero que esto ayude
Referencia del artículo:
Mr. Hua Pants: Mr. Hua Pants
Código de este artículo: github para estrella