• 在 Node.js 中实现基于角色的访问控制


    在 Node.js 中实现基于角色的访问控制

    基于角色的访问控制 (Role-Based Access Control,缩写RBAC) 是应用程序安全性的一个重要方面。它提供了一种结构化方法,可以根据组织或应用程序中用户的角色来管理和限制对资源的访问。在本文中,我们将探讨 RBAC 的概念,讨论其优点,并引导完成在 Node.js 中实现 RBAC 的过程。

    基于角色的访问控制简介

    什么是 RBAC

    RBAC是一种将系统访问限制为授权用户的安全概念。在 RBAC 中,访问权限与角色相关联,用户被分配一个或多个角色。这些角色定义用户可以在系统中执行哪些操作或操作。

    RBAC 通过集中权限来简化访问控制,使管理员能够在较高级别管理用户访问。它通过确保用户仅拥有执行其角色所需的权限来增强安全性,从而降低未经授权的操作的风险。

    RBAC 的好处

    RBAC 具有许多好处,包括:

    • 安全性:RBAC 能最大限度地降低应用程序内未经授权的访问或操作的风险,从而减少安全漏洞。
    • 简单性:它通过将权限分组到角色来简化用户访问管理,使管理更加简单。
    • 可扩展性:RBAC 具有高度可扩展性,使其适用于小型和大型应用程序。
    • 合规性:许多监管框架(例如 GDPRHIPAA)需要强大的访问控制机制。
    • 可审核性:RBAC 允许我们跟踪和审核用户操作,这对于识别安全漏洞至关重要。

    项目结构

    这是我们将在本教程中使用的基本项目结构:

    my-rbac-app/
    │
    ├── package.json
    ├── package-lock.json
    ├── index.js
    ├── models/
    │   └── user.js
    ├── routes/
    │   └── auth.js
    │   └── tasks.js
    ├── controllers/
    │   └── authController.js
    │   └── tasksController.js
    ├── middleware/
    │   └── rbacMiddleware.js
    │
    └── config/
        └── roles.json
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    用户角色和权限

    定义角色和权限

    RBAC 中,角色代表组织内的工作职能或头衔,权限是可以执行的操作或操作。让我们首先为我们的项目定义一些角色和权限。

    在目录中创建一个roles.json文件:

    {
      "roles": [
        {
          "name": "admin",
          "permissions": [
            "create_task",
            "read_task",
            "update_task",
            "delete_task"
          ]
        },
        {
          "name": "manager",
          "permissions": [
            "create_task",
            "read_task",
            "update_task"
          ]
        },
        {
          "name": "employee",
          "permissions": [
            "create_task",
            "read_task"
          ]
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里,我们定义了三个角色:“管理员”、“经理”和“员工”,每个角色都具有与任务管理相关的不同权限集。

    存储角色和权限数据

    现在,让我们创建模型来表示角色和权限。在models/目录中,创建一个role.js文件:

    // models/role.js
    
    const roles = require('../config/roles.json');
    
    class Role {
      constructor() {
        this.roles = roles.roles;
      }
    
      getRoleByName(name) {
        return this.roles.find((role) => role.name === name);
      }
    
      getRoles() {
        return this.roles;
      }
    }
    
    module.exports = Role;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在上面的代码中,我们创建了一个从文件中读取角色和权限的类Role。我们还提供按名称检索角色或获取所有角色列表的方法。

    接下来,在同一目录中创建一个models/permissions.js文件:

    // models/permissions.js
    
    class Permissions {
      constructor() {
        this.permissions = [];
      }
    
      getPermissionsByRoleName(roleName) {
        const role = roles.roles.find((r) => r.name === roleName);
        return role ? role.permissions : [];
      }
    }
    
    module.exports = Permissions;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Permissions允许我们根据角色名称获取权限。在为用户分配角色并检查 RBAC 中间件中的权限时,我们将使用这些模型。

    定义角色和权限并建立模型后,让我们继续进行用户身份验证。

    用户认证

    实施用户认证

    用户身份验证是 RBAC 的基本组成部分。我们将使用passport库来处理身份验证。
    首先,安装所需的依赖项:

    npm install passport mongoose passport-local passport-local-mongoose express-session
    
    • 1

    现在,使用 MongoosePassport 创建用户模型models/user.js

    // models/user.js
    
    const mongoose = require('mongoose');
    const passportLocalMongoose = require('passport-local-mongoose');
    
    const userSchema = new mongoose.Schema({
      username: String,
      password: String,
      role: String,
    });
    
    userSchema.plugin(passportLocalMongoose);
    
    const User = mongoose.model('User', userSchema);
    
    module.exports = User;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在上面的代码中,我们创建了一个包含必要字段的用户模型,并用passport-local-mongoose来实现用户身份验证。

    角色分配

    现在,当用户注册或创建时,我们需要为他们分配角色。

    // controllers/authController.js
    
    const User = require('../models/user');
    const Role = require('../models/role');
    
    // 注册用户
    exports.registerUser = (req, res) => {
      const { username, password, role } = req.body;
      const user = new User({ username, role });
    
      User.register(user, password, (err) => {
        if (err) {
          console.error(err);
          return res.status(500).json({ error: err.message });
        }
        res.json({ message: '用户注册成功' });
      });
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在上面的代码中,我们创建一个新用户并在注册期间指定其角色。用户的角色将根据应用程序的业务逻辑来定义。

    完成用户身份验证和角色分配后,我们现在可以继续创建基于角色的中间件来保护路由。

    基于角色的中间件

    创建 RBAC 中间件

    Node.js 中的中间件对于处理路由保护和用户授权等任务至关重要。我们将创建 RBAC 中间件来检查用户是否具有访问特定路由的必要权限。

    // middleware/rbacMiddleware.js
    
    const Role = require('../models/role');
    const Permissions = require('../models/permissions');
    
    // 判断用户是否存在访问权限
    exports.checkPermission = (permission) => {
      return (req, res, next) => {
        const userRole = req.user ? req.user.role : 'anonymous';
        const userPermissions = new Permissions().getPermissionsByRoleName(userRole);
    
        if (userPermissions.includes(permission)) {
          return next();
        } else {
          return res.status(403).json({ error: 'Access denied' });
        }
      };
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在此中间件中,我们从用户的会话中提取用户的角色,并检查该角色是否具有访问路由所需的权限。如果用户拥有必要的权限,则允许他们继续;否则,将发送403 Forbidden响应。

    保护路由

    要使用 RBAC 中间件保护特定路由,需要导入中间件函数并将其应用到路由处理程序中的所需路由。

    // routes/tasks.js
    
    const express = require('express');
    const router = express.Router();
    const rbacMiddleware = require('../middleware/rbacMiddleware');
    
    // 引入控制器
    const tasksController = require('../controllers/tasksController');
    
    // 使用中间件
    router.get('/tasks', rbacMiddleware.checkPermission('read_task'), tasksController.getAllTasks);
    
    module.exports = router;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    现在,tasks路由受到保护,只有具有read_task权限的用户才能访问它。

    RBAC 中间件就位后,我们现在可以继续构建一个示例项目来查看 RBAC 的实际应用。

    示例项目:RBAC 实际应用

    在本节中,我们将使用 RBAC 构建一个简单的任务管理系统。我们将定义角色和权限,创建用户身份验证,为用户分配角色,并根据用户的角色和权限保护路由。

    构建一个简单的任务管理系统

    让我们首先定义任务管理系统的基本路由。创建一个新文件tasks.js

    // routes/tasks.js
    
    const express = require('express');
    const router = express.Router();
    const rbacMiddleware = require('../middleware/rbacMiddleware');
    
    // 引入控制器
    const tasksController = require('../controllers/tasksController');
    
    // 使用中间件
    router.get('/tasks', rbacMiddleware.checkPermission('read_task'), tasksController.getAllTasks);
    router.post('/tasks', rbacMiddleware.checkPermission('create_task'), tasksController.createTask);
    router.put('/tasks/:id', rbacMiddleware.checkPermission('update_task'), tasksController.updateTask);
    router.delete('/tasks/:id', rbacMiddleware.checkPermission('delete_task'), tasksController.deleteTask);
    
    module.exports = router;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在此代码中,我们定义了用于列出、创建、更新和删除任务的路由。每个路由都受到 RBAC 中间件的保护,该中间件在允许访问之前检查用户的权限。

    定义角色和权限

    在为用户分配角色之前,我们先定义应用程序的角色和权限。在config/roles.json文件中,指定角色及其关联的权限:

    {
      "roles": [
        {
          "name": "admin",
          "permissions": ["create_task", "read_task", "update_task", "delete_task"]
        },
        {
          "name": "manager",
          "permissions": ["create_task", "read_task", "update_task"]
        },
        {
          "name": "employee",
          "permissions": ["create_task", "read_task"]
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    我们定义了三个角色:“管理员”、“经理”和“员工”,每个角色都有不同的访问级别。

    实施认证和授权

    controllers/authController.js文件中,实现用户注册和登录功能:

    // controllers/authController.js
    
    const User = require('../models/user');
    const Role = require('../models/role');
    
    exports.registerUser = (req, res) => {
      const { username, password, role } = req.body;
      const user = new User({ username, role });
    
      User.register(user, password, (err) => {
        if (err) {
          console.error(err);
          return res.status(500).json({ error: err.message });
        }
        res.json({ message: 'User registered successfully' });
      });
    };
    
    exports.loginUser = (req, res) => {
    
      const { username, password } = req.body;
    
      User.authenticate(username, password, (err, user) => {
        if (err || !user) {
          return res.status(401).json({ error: 'Invalid credentials' });
        }
        req.session.userId = user._id; 
        res.json({ message: 'Login successful' });
      });
    };
    exports.logoutUser = (req, res) => {
      
      if (req.session) {
        req.session.destroy((err) => {
          if (err) {
            return res.status(500).json({ error: err.message });  
          }
          res.json({ message: 'Logged out successfully' });
        });
      } else {
        res.json({ message: 'Not logged in' });
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    loginUserlogoutUser函数中,可以根据应用程序的需要实现登录和注销逻辑。

    结论

    在本文中,我们探讨了基于角色的访问控制 (RBAC) 的概念,并演示了如何在 Node.js 应用程序中实现它。我们介绍了角色和权限定义、用户身份验证、角色分配、基于角色的中间件,并创建了一个示例任务管理系统来展示 RBAC 的实际应用。

    通过实施 RBAC,我们可以显着增强 Node.js 应用程序的安全性,有效控制用户访问,并降低安全漏洞的风险。

  • 相关阅读:
    46-设计问题-最小栈
    ubuntu18安装常用软件命令
    Qt项目实战--网络编程简单BC端聊天系统
    vscode + conda+ ffmpeg + numpy 的安装方式
    【医学大模型】Text2MDT :从医学指南中,构建医学决策树
    并发——中断机制
    centos Hadoop伪分布模式安装-ssh免密登录
    ubuntu右上角的网络连接图标消失解决办法
    c++ 继承
    抗原检测统计小程序
  • 原文地址:https://blog.csdn.net/qq_42880714/article/details/133979900