Blog Building Based on Al egg Framework-Privilege Control

Keywords: Front-end Session Database Redis git

Related articles

Blog Building Based on Al egg Framework (1) - Development Preparations
Building Blog Based on Al egg Framework (2) - Hello World
Building Blog Based on Al egg Framework (3) - Registration and Login
Blog Building Based on Al egg Framework (4) - Privilege Control
Building Blog Based on Al egg Framework (5) - Top Navigation Bar
Building Blog Based on Al egg Framework (6) - Browsing and Publishing Articles
Blog Building Based on Al egg Framework (7) - Editing Articles

git

https://github.com/ZzzSimon/e...
Just give me a compliment if you like it.

text

In the last article, we implemented user registration and login, and then we need to control user rights, such as: ordinary users can only comment, administrators can publish articles, top administrators can modify user rights and so on.
Since permission control is a general function, we make this function into middleware. About middleware:

Official documents: https://eggjs.org/zh-cn/basic...

functional design

  1. A user corresponds to a role
  2. You can configure pages and interfaces that a role does not have permission to use through configuration files
  3. You can configure path s that do not need to authenticate users and privileges. For example: related pages and interfaces for login and registration
  4. The path that can be accessed only after login, otherwise jump to the login page.

User table, add role (role) field

configuration file

We add the following in config/config.default.js:

        auth : {
            noAuth:['/login.htm','/user/login','/register.htm','/user/register'],
            noPermission:{
                admin:[],
                manager:['/admin.htm'],
                user:['/admin.htm','/edit.htm']
            }
        }

Among them:
noAuth nodes are configured with path s that can be accessed without authentication
The noPermission node configures path s that each role has no access to

Auh.js middleware code

We create the app/middleware/auth.js file:

module.exports = (options, app) => {
    return async function auth(ctx, next) {
        //If user session does not fail
        if (typeof (ctx.session.user) !== 'undefined') {
            const username = ctx.session.user.username;
            //There are two ways to do this. The first way is to check roles every time. The advantages are: real-time, role change is insensitive to users. Disadvantage: Low efficiency of database searching, redis can be considered
            //The second is to put role information into session, which has the advantage of no need of database search and high efficiency. Disadvantage: Additional logic is needed to handle old sessions when roles change, otherwise the client's user roles cannot be updated in real time.
            const role = await ctx.service.user.getRoleByUsername(username);
            const noPerList = options.noPermission[role];
            if (noPerList && !noPerList.includes(ctx.path)) {
                await next();
            } else {
                ctx.body = 'No permission, please contact the webmaster!';
            }
            //No permissions are required to log in to the registration page
        } else if (options.noAuth.includes(ctx.path)) {
            await next();
            //If session fails, redirect to the login page
        } else {
            ctx.redirect('/login.htm')
        }
    }
};

Effect

We create a user and give him the user role. As can be seen from the configuration file, the user role has no access to the / edit.htm path. As shown in the picture:

Regular matching

If there are more pages, or some paths with parameters are dynamic, we need rules to filter paths. Regular matching is needed at this point. We modify the auth.js file:

module.exports = (options, app) => {
    function isNoPer(noPerList,path) {
        for (let i = 0;i<noPerList.length;i++){
            const patt=new RegExp(noPerList[i]);
            if (patt.test(path)) {
                return true;
            }
        }
        return false;
    }
    return async function auth(ctx, next) {
        //If user session does not fail
        if (typeof (ctx.session.user) !== 'undefined') {
            const username = ctx.session.user.username;
            //There are two ways to do this. The first way is to check roles every time. The advantages are: real-time, role change is insensitive to users. Disadvantage: Low efficiency of database searching, redis can be considered
            //The second is to put role information into session, which has the advantage of no need of database search and high efficiency. Disadvantage: Additional logic is needed to handle old sessions when roles change, otherwise the client's user roles cannot be updated in real time.
            const role = await ctx.service.user.getRoleByUsername(username);
            const noPerList = options.noPermission[role];
            if (noPerList && !isNoPer(noPerList,ctx.path)) {
                await next();
            } else {
                ctx.body = 'No permission, please contact the webmaster!';
            }
            //No permissions are required to log in to the registration page
        } else if (options.noAuth.includes(ctx.path)) {
            await next();
            //If session fails, redirect to the login page
        } else {
            ctx.redirect('/login.htm')
        }
    }
};

At this point, our configuration file can support regular expressions:

        auth : {
            noAuth:['/login.htm','/user/login','/register.htm','/user/register'],
            noPermission:{
                admin:[],
                manager:['/admin.htm'],
                user:['/admin.htm','/edit.*']
            }
        }

Ending

If you find it useful after reading, please give the author a favorite! Thank you!

Posted by ingoruberg on Sun, 13 Oct 2019 21:15:57 -0700