开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
什么是权限管理
权限是特定资源的访问许可
例如:用户没有登录时只能访问登录注册界面,而不能转跳到其它界面;管理员和普通用户,管理员的权限比普通用户的要高,部分功能是不向普通用户开放的。
所以前端要做的就是根据用户的不同,展示用户权限范围内的内容,阻止用户发起超越自己权限的请求。
实现权限管理
接口权限
接口权限由前后端配合完成
后端,以koa为例,使用 koajwt中间件并配置白名单
// 登录验证白名单
app.use(koajwt({ secret: config.SECRET }).unless({
path: [
/^\/user\/login/, // 登陆接口
/^\/user\/register/ // 注册
]
}))
前端的任务是,对请求拦截查看用户权限,或者在登录时过期进行处理
// 请求拦截
axios.interceptors.request.use(config => {
config.headers['token'] = cookie.get('token')
return config
})
// 响应拦截
axios.interceptors.response.use(res=>{},{response}=>{
if (response.data.code === 40099 || response.data.code === 40098) { //token过期或者错误
router.push('/login')
}
})
页面权限
主要思路
- 根据用户权限建立不同的
routes,在登录之前只挂载白名单里的页面,在登录之后异步获取该用户的routes,再通过addRoutes动态挂载 - 通过配置 meta中的roles,再跳转页面时经过路由守卫判断该用户是否具有权限访问该页面,没有权限则转跳到403/404
function hasPermission(router, accessMenu) {
if (whiteList.indexOf(router.path) !== -1) {
return true;
}
let menu = Util.getMenuByName(router.name, accessMenu);
if (menu.name) {
return true;
}
return false;
}
Router.beforeEach(async (to, from, next) => {
if (getToken()) {
let userInfo = store.state.user.userInfo;
if (!userInfo.name) {
try {
await store.dispatch("GetUserInfo")
await store.dispatch('updateAccessMenu')
if (to.path === '/login') {
next({ name: 'home_index' })
} else {
//Util.toDefaultPage([...routers], to.name, router, next);
next({ ...to, replace: true }) //菜单权限更新完成,重新进一次当前路由
}
}
catch (e) {
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next()
} else {
next('/login')
}
}
} else {
if (to.path === '/login') {
next({ name: 'home_index' })
} else {
if (hasPermission(to, store.getters.accessMenu)) {
Util.toDefaultPage(store.getters.accessMenu,to, routes, next);
} else {
next({ path: '/403',replace:true })
}
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next()
} else {
next('/login')
}
}
let menu = Util.getMenuByName(to.name, store.getters.accessMenu);
Util.title(menu.title);
});
Router.afterEach((to) => {
window.scrollTo(0, 0);
});
按钮权限
- 页面中获取用户角色和权限 使用
v-if - 配置路由中
meta: {btnPermissions: ['admin']}
封装自定义指令
import { Directive } from "vue";
import type { DirectiveBinding } from "vue";
export const auth: Directive = {
mounted(el: HTMLElement, binding: DirectiveBinding,vnode:VNode) {
const { value } = binding;
if (value) {
const authRoles = value;
// const hasAuth = usePermissionStoreHook().buttonAuth.includes(authRoles);
btnPermissionsArr = vnode.context.$route.meta.btnPermissions;
if (!hasAuth) {
el.parentNode.removeChild(el);
}
} else {
throw new Error("need roles! Like v-auth=\"['admin','test']\"");
}
}
};
function _has = function (value:Array) {
let isExist = false;
// 获取用户按钮权限
let btnPermissionsStr = sessionStorage.getItem("btnPermissions");
if (btnPermissionsStr == undefined || btnPermissionsStr == null) {
return false;
}
if (value.indexOf(btnPermissionsStr) > -1) {
isExist = true;
}
return isExist;
}
使用v-auth