首頁  >  文章  >  web前端  >  nodejs acl的使用者權限管理詳解

nodejs acl的使用者權限管理詳解

亚连
亚连原創
2018-05-30 11:13:362718瀏覽

這篇文章主要介紹了nodejs acl的使用者權限管理詳解,現在分享給大家,也給大家做個參考。

說明

Q: 這個工具用來做什麼的呢

A: 使用者有不同的權限,比如管理員,vip,普通使用者,每個使用者對應訪問api,頁面都不一樣

nodejs有兩個比較有名的權限管理模組一個是acl 一個是rbac 綜合對比了一下最終在做專案的時候選擇了acl

功能清單:

  1. addUserRoles //為某使用者新增角色

  2. removeUserRoles //移除某使用者角色

  3. userRoles //取得某使用者所有角色

  4. #roleUsers //取得所有是此角色的使用者

  5. hasRole // 某使用者是否是某角色

  6. addRoleParents //為某個角色增加父角色

  7. #removeRoleParents //移除某覺得的某父角色或所有父角色

  8. removeRole //移除某角色

  9. removeResource //移除某資源

  10. allow //為某些角色增加某些資源的某些權限

  11. removeAllow //移除某些角色的某些資源的某些權限

  12. allowedPermissions //查詢某人的所有資源及其權限

  13. isAllowed //查詢某人是否有某資源的某權限

  14. areAnyRolesAllowed //查詢某角色是否有某資源的某權限

  15. whatResources //查詢某角色有哪些資源

  16. middleware //middleware for express

  17. #backend //指定方式(mongo/redis…)

  1. ##ACL名詞及其主要方法

  2. roles 角色

#removeRole


addRoleParents

  1. allow

  2. #removeAllow

  3. ##resources 資源

  4. #whatResources

  5. removeResource

  6. #permissions 權限

  7. users 使用者
  8. allowedPermissions
  9. isAllowed

    #addUserRoles
  1. removeUserRoles
  2. #userRoles
  3. roleUsers

#hasRole

areAnyRolesAllowed

使用方法

建立起設定檔

使用者登入後指派對應的權限

需要控制的地方使用acl做校檢

設定檔

const Acl = require('acl');
const aclConfig = require('../conf/acl_conf');

module.exports = function (app, express) {
  const acl = new Acl(new Acl.memoryBackend()); // eslint-disable-line

  acl.allow(aclConfig);

  return acl;
};

// acl_conf

module.exports = [
  {
    roles: 'normal', // 一般用户
    allows: [
      { resources: ['/admin/reserve'], permissions: ['get'] },
    ]
  },
  {
    roles: 'member', // 会员
    allows: [
      { resources: ['/admin/reserve', '/admin/sign'], permissions: ['get'] },
      { resources: ['/admin/reserve/add-visitor', '/admin/reserve/add-visitor-excel', '/admin/reserve/audit', '/admin/sign/ban'], permissions: ['post'] },
    ]
  },
  {
    roles: 'admin',  // 管理
    allows: [
      { resources: ['/admin/reserve', '/admin/sign', '/admin/set'], permissions: ['get'] },
      { resources: ['/admin/set/add-user', '/admin/set/modify-user'], permissions: ['post'] },
    ]
  },
  {
    roles: 'root', // 最高权限
    allows: [
      { resources: ['/admin/reserve', '/admin/sign', '/admin/set'], permissions: ['get'] },
    ]
  }
];

  1. 校檢

這裡是結合express做校檢...結果發現acl自己提供的中間件太雞肋了,這裡就重寫了一個。

function auth() {
    return async function (req, res, next) {
      let resource = req.baseUrl;
      if (req.route) { // 正常在control中使用有route属性 但是使用app.use则不会有
        resource = resource + req.route.path;
      }
      console.log('resource', resource);

      // 容错 如果访问的是 /admin/sign/ 后面为 /符号认定也为过
      if (resource[resource.length - 1] === '/') {
        resource = resource.slice(0, -1);
      }

      let role = await acl.hasRole(req.session.userName, 'root');

      if (role) {
        return next();
      }

      let result = await acl.isAllowed(req.session.userName, resource, req.method.toLowerCase());
      // if (!result) {
      //   let err = {
      //     errorCode: 401,
      //     message: '用户未授权访问',
      //   };
      //   return res.status(401).send(err.message);
      // }
      next();
    };
  }

有點要說明的是express.Router支援導出一個Router模組再在app.use使用,但是如果你這樣使用app.use('/ admin/user',auth(), userRoute); 那麼是在auth這個函數是取得不到req.route 這個屬性的。因為acl對存取權限做的是強匹配,所以需要有一定的容錯

登入的權限分配

result為資料庫查詢出來的使用者資訊,或是後台api返給的使用者資訊,這裡的switch可以使用設定檔的形式,因為我這邊本次項目只有三個權限,所以就在這裡簡單寫了一下。

let roleName = 'normal';

  switch (result.result.privilege) {
    case 0:
      roleName = 'admin';
      break;
    case 1:
      roleName = 'normal';
      break;
    case 2:
      roleName = 'member';
      break;
  }

  if (result.result.name === 'Nathan') {
    roleName = 'root';
  }

  req.session['role'] = roleName;
  // req.session['role'] = 'root';  // test
  acl.addUserRoles(result.result.name, roleName);
  // acl.addUserRoles(result.result.name, 'root'); // test

  1. pug頁面中的渲染邏輯控制

  2. 在express pug中app.locals.auth= async function (){} 這個寫法在pug渲染的時候是不會得出最終結果的,因為pug是同步的,那麼我如何控制當前頁面或者說當前頁面的按鈕用戶是否有權限展示出來, 這裡通用的做法有
  3. 使用者登入的時候有一個路由表和元件表然後在渲染的時候根據這個表去渲染

在需要權限控制的地方,使用函數來判斷用戶是否有權限訪問

#########我這裡採用的是結局方案2.因為比較方便, 但是問題來了express pug是不支持異步的寫法,而acl提供給我們的全是異步的, 因為時間原因,我沒有去深究裡面的判斷,而是採用了一種耦合性比較高但是比較方便的判斷方法.#########
app.locals.hasRole = function (userRole, path, method = 'get') {

  if (userRole === 'root') {
    return true;
  }

  const current = aclConf.find((n) => {
    return n['roles'] === userRole;
  });

  let isFind = false;
  for (let i of current.allows) {
    const currentPath = i.resources; // 目前数组第一个为单纯的get路由
    isFind = currentPath.includes(path);

    if (isFind) {
      // 如果找到包含该路径 并且method也对应得上 那么则通过
      if (i.permissions.includes(method)) {
        break;
      }

      // 如果找到该路径 但是method对应不上 则继续找.
      continue;
    }
  }

  return isFind;
};
#########上述程式碼頁比較簡單, 去遍歷acl_conf,查找用戶是否有當前頁面的或者按鈕的權限因為acl_conf在加載的時候就已經被寫入內存了,所以性能消耗不會特別大。比如下面的例子。 #########
if hasRole(user.role, '/admin/reserve/audit', 'post')
          .col.l3.right-align
            a.waves-effect.waves-light.btn.margin-right.blue.font12.js-reviewe-ok 同意
            a.waves-effect.waves-light.btn.pink.accent-3.font12.js-reviewe-no 拒绝
############結束##########依賴acl這個元件可以快速打造一個使用者的權限管理模組。但是還有個問題 也急速那個app.locals.hasRole函數, 如果你使用removeAllow動態改變了用戶的權限表,那麼hasRole函數就很麻煩了。所以在這種情況下有以下幾個解############從acl原始碼入手############每次渲染的時候就把資料準備好###############
const hasBtn1Role = hasRole(user.role, '/xxx','get');
res.render('a.pug',{hasBtn1Role})
#######

上面是我整理給大家的,希望未來會對大家有幫助。

相關文章:

Angular中使用better-scroll插件的方法_AngularJS

##Angularjs實作控制器之間通訊方式實例總結

JavaScript程式碼實作txt檔案的上傳預覽功能

##

以上是nodejs acl的使用者權限管理詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn