Detailed description of nodejs acl user permission management, nodejsacl
Description
Q: What is this tool used?
A: users have different permissions, such as the administrator, vip, and common users. Each user accesses an api on different pages.
Nodejs has two well-known permission management modules. One is acl, and the other is rbac. After a comprehensive comparison, the acl is selected during project creation.
Function list:
- AddUserRoles // Add a role to a user
- RemoveUserRoles // remove a User Role
- UserRoles // obtain all roles of a user
- RoleUsers // obtain all users with this role
- HasRole // whether a user is a role
- AddRoleParents // Add a parent role to a role
- RemoveRoleParents // remove a parent role or all parent roles
- RemoveRole // remove a role
- RemoveResource // remove a resource
- Allow // Add some permissions for some resources to some roles
- RemoveAllow // remove some permissions for certain resources of certain roles
- AllowedPermissions // query all resources of a person and their Permissions
- IsAllowed // query whether a person has certain permissions for a resource.
- AreAnyRolesAllowed // query whether a role has a certain resource permission.
- WhatResources // query resources of a role
- Middleware // middleware for express
- Backend // specify the mode (mongo/redis ...)
ACL nouns and their main methods
Roles role
- RemoveRole
- AddRoleParents
- Allow
- RemoveAllow
Resources
- WhatResources
- RemoveResource
Permissions permission
Users user
- AllowedPermissions
- IsAllowed
- AddUserRoles
- RemoveUserRoles
- UserRoles
- RoleUsers
- HasRole
- AreAnyRolesAllowed
Usage
- Create a configuration file
- After logon, the user is assigned the corresponding permissions.
- Use acl for verification where control is needed
Configuration File
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_confmodule.exports = [{roles: 'normal', // common user allows: [{resources: ['/admin/reserv'], permissions: ['get']},]}, {roles: 'member', // member allows: [{resources: ['/admin/reserv','/admin/sign'], permissions: ['get']}, {resources: ['/admin/reserve/add-visitor ', '/admin/reserve/add-visitor-excel', '/admin/reserve/audit', '/admin/sign/ban'], permissions: ['post']},]}, {roles: 'admin', // manage allows: [{resources: ['/admin/reserv ', '/admin/sign','/admin/set'], permissions: ['get']}, {resources: ['/admin/set/add-user ', '/admin/set/modify-user'], permissions: ['post']},]}, {roles: 'root', // maximum permission allows: [{resources: ['/admin/reserv','/admin/sign', '/admin/set'], permissions: ['get']},]}];
School Inspection
Here is a school check in conjunction with express... the result shows that the middleware provided by the acl itself is too bad. Here we rewrite one.
Function auth () {return async function (req, res, next) {let resource = req. baseUrl; if (req. route) {// normally, the route attribute is used in the control but the app is used. use does not have resource = resource + req. route. path;} console. log ('resource', resource); // fault tolerance if/admin/sign/is accessed, it is also identified as if (resource [resource. length-1] = '/') {resource = resource. slice (0,-1);} let role = await acl. hasRole (req. session. userName, 'root'); I F (role) {return next ();} let result = await acl. isAllowed (req. session. userName, resource, req. method. toLowerCase (); // if (! Result) {// let err = {// errorCode: 401, // message: 'user unauthorized access', //}; // return res. status (401 ). send (err. message); //} next ();};}
It should be noted that express. the Router module can be exported to the app. use, but if you use the app in this way. use ('/admin/user', auth (), userRoute); then the req cannot be obtained in the auth function. route. Because acl strongly matches access permissions, it must be fault tolerant.
Logon permission allocation
The result is the user information queried by the database, or the user information returned by the background api. The switch here can be in the form of a configuration file, because I have only three permissions for this project, so I simply wrote it here.
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
Rendering logic control in pug pages
In express + pug app. locals. auth = async function () {} does not get the final result during pug rendering, because pug is synchronous, how can I control whether the button user on the current page or the current page has the permission to display it? The common practices here are:
- When you log on, you have a route table and component table, which are then rendered based on the table during rendering.
- Where permission control is required, use a function to determine whether a user has access permissions.
I am using the Final Solution 2. it is convenient, but the problem is that express + pug does not support asynchronous writing, while acl provides us with asynchronous writing. Due to time reasons, I did not go into the judgment, however, a high coupling but convenient judgment method is adopted.
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; // The first in the current array is the simple get route isFind = currentPath. includes (path); if (isFind) {// if the path is found and the method corresponds to it, then the if (I. permissions. includes (method) {break;} // if the path is found but the method does not match, continue to find it. continue ;}} return isFind ;};
The above code page is relatively simple. Traverse acl_conf to check whether the user has the permission to access the current page or the button. Because acl_conf has been written into the memory during loading, the performance consumption will not be very high. For example, the following example.
If hasRole (user. role, '/admin/reserve/audit', 'post'). col. l3.right-align a.waves-effect.wav es-light.btn.margin-right.blue.font12.js-reviewe-ok agrees that the.waves-effect.wav es-light.btn.pink.accent-3.font12.js-reviewe-no rejects
End
Using the acl component, you can quickly create a user permission management module. However, there is another problem: the app. locals. hasRole function. If you use removeAllow to dynamically change the user's permission table, the hasRole function will be very troublesome. Therefore, the following solutions are available in this case:
- Starting with the acl source code
- Prepare the data for each rendering.
const hasBtn1Role = hasRole(user.role, '/xxx','get');res.render('a.pug',{hasBtn1Role})
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.