权限管理

131 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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