Sequelize 实践:实现权限管理

在 web 应用程序中,权限管理是非常重要的一部分。它可以控制用户对某些功能、资源或数据的访问权限。Sequelize 是一个流行的 Node.js ORM(对象关系映射)框架,它可以帮助我们更方便地操作数据库。本文将介绍如何使用 Sequelize 实现权限管理。

数据库设计

在开始实现权限管理之前,我们需要先设计数据库。假设我们有以下两个表:

用户表(users)

字段名 类型 描述
id INTEGER 用户 ID
username STRING 用户名
password STRING 密码
email STRING 邮箱
role INTEGER 用户角色
created_time DATETIME 创建时间
updated_time DATETIME 最后更新时间

权限表(permissions)

字段名 类型 描述
id INTEGER 权限 ID
name STRING 权限名称
description STRING 权限描述
created_time DATETIME 创建时间
updated_time DATETIME 最后更新时间

用户表中的 role 字段表示用户的角色,我们可以将其定义为一个整数。权限表中的 name 字段表示权限的名称,description 字段表示权限的描述。

模型定义

在 Sequelize 中,我们需要定义模型来映射数据库中的表。在本文中,我们需要定义两个模型:User 和 Permission。下面是它们的定义。

// User 模型
const User = sequelize.define('user', {
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  username: Sequelize.STRING,
  password: Sequelize.STRING,
  email: Sequelize.STRING,
  role: Sequelize.INTEGER,
  created_time: Sequelize.DATE,
  updated_time: Sequelize.DATE,
});

// Permission 模型
const Permission = sequelize.define('permission', {
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  name: Sequelize.STRING,
  description: Sequelize.STRING,
  created_time: Sequelize.DATE,
  updated_time: Sequelize.DATE,
});

在这里,我们使用了 sequelize.define() 方法来定义模型。其中,第一个参数是模型的名称,第二个参数是模型的属性定义。在属性定义中,我们使用了 Sequelize 提供的一些数据类型,如 Sequelize.STRING 和 Sequelize.INTEGER。

关联定义

在权限管理中,用户和权限之间存在多对多的关系。一个用户可以拥有多个权限,一个权限也可以被多个用户拥有。我们需要在模型中定义这种关系。

// 定义 User 和 Permission 的多对多关系
User.belongsToMany(Permission, { through: 'UserPermission' });
Permission.belongsToMany(User, { through: 'UserPermission' });

在这里,我们使用了 belongsToMany() 方法来定义多对多关系。其中,第一个参数是关联的模型,第二个参数是关联选项。通过选项中的 through 属性,我们可以指定关联表的名称。

权限控制

在实现权限管理时,我们需要对用户的访问权限进行控制。我们可以在路由层、控制器层或服务层中进行权限控制。在本文中,我们将在服务层中进行权限控制。

首先,我们需要定义一个中间件函数,用于检查用户的权限。

// 检查用户是否拥有指定的权限
function checkPermission(permissionName) {
  return async (req, res, next) => {
    const { user } = req;

    // 如果用户未登录,则返回 401 错误
    if (!user) {
      return res.status(401).send('Unauthorized');
    }

    // 如果用户不具备指定的权限,则返回 403 错误
    const hasPermission = await user.hasPermission(permissionName);
    if (!hasPermission) {
      return res.status(403).send('Forbidden');
    }

    next();
  };
}

在这里,我们定义了一个 checkPermission() 函数,它返回一个中间件函数。中间件函数接收三个参数:req、res 和 next。在函数中,我们首先检查用户是否已登录。如果用户未登录,则返回 401 错误。然后,我们检查用户是否具备指定的权限。如果用户不具备指定的权限,则返回 403 错误。最后,如果用户具备指定的权限,则调用 next() 函数,将控制权交给下一个中间件或路由处理程序。

在检查用户权限时,我们使用了 user.hasPermission() 方法。这是 Sequelize 自动生成的方法,用于检查用户是否拥有指定的权限。我们可以在 User 模型中定义这个方法。

// User 模型中定义 hasPermission() 方法
User.prototype.hasPermission = async function (permissionName) {
  const permission = await Permission.findOne({ where: { name: permissionName } });
  if (!permission) {
    return false;
  }

  const hasPermission = await this.hasPermission(permission);
  return hasPermission;
};

在这里,我们定义了一个 User.prototype.hasPermission() 方法。该方法接收一个参数 permissionName,表示要检查的权限名称。然后,我们在 Permission 表中查找具有指定名称的权限。如果找不到,则返回 false。否则,我们使用 this.hasPermission() 方法检查用户是否拥有该权限。

示例代码

下面是一个完整的示例代码,演示如何使用 Sequelize 实现权限管理。

const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
  dialect: 'sqlite',
  storage: 'database.sqlite',
});

// User 模型
const User = sequelize.define('user', {
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  username: Sequelize.STRING,
  password: Sequelize.STRING,
  email: Sequelize.STRING,
  role: Sequelize.INTEGER,
  created_time: Sequelize.DATE,
  updated_time: Sequelize.DATE,
});

// Permission 模型
const Permission = sequelize.define('permission', {
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  name: Sequelize.STRING,
  description: Sequelize.STRING,
  created_time: Sequelize.DATE,
  updated_time: Sequelize.DATE,
});

// 定义 User 和 Permission 的多对多关系
User.belongsToMany(Permission, { through: 'UserPermission' });
Permission.belongsToMany(User, { through: 'UserPermission' });

// User 模型中定义 hasPermission() 方法
User.prototype.hasPermission = async function (permissionName) {
  const permission = await Permission.findOne({ where: { name: permissionName } });
  if (!permission) {
    return false;
  }

  const hasPermission = await this.hasPermission(permission);
  return hasPermission;
};

// 检查用户是否拥有指定的权限
function checkPermission(permissionName) {
  return async (req, res, next) => {
    const { user } = req;

    // 如果用户未登录,则返回 401 错误
    if (!user) {
      return res.status(401).send('Unauthorized');
    }

    // 如果用户不具备指定的权限,则返回 403 错误
    const hasPermission = await user.hasPermission(permissionName);
    if (!hasPermission) {
      return res.status(403).send('Forbidden');
    }

    next();
  };
}

// 创建用户
async function createUser(username, password, email, role) {
  const user = await User.create({ username, password, email, role });
  return user;
}

// 创建权限
async function createPermission(name, description) {
  const permission = await Permission.create({ name, description });
  return permission;
}

// 为用户添加权限
async function grantPermission(userId, permissionName) {
  const user = await User.findByPk(userId);
  const permission = await Permission.findOne({ where: { name: permissionName } });
  await user.addPermission(permission);
}

// 使用示例代码
(async () => {
  // 创建用户和权限
  const user1 = await createUser('user1', 'password1', 'user1@example.com', 1);
  const user2 = await createUser('user2', 'password2', 'user2@example.com', 2);
  const permission1 = await createPermission('permission1', 'Permission 1');
  const permission2 = await createPermission('permission2', 'Permission 2');

  // 为用户添加权限
  await grantPermission(user1.id, 'permission1');
  await grantPermission(user2.id, 'permission2');

  // 检查用户是否具备指定权限
  const hasPermission1 = await user1.hasPermission('permission1');
  const hasPermission2 = await user1.hasPermission('permission2');
  console.log(hasPermission1); // true
  console.log(hasPermission2); // false

  // 使用中间件检查用户权限
  const app = express();
  app.use(checkPermission('permission1'));
  app.get('/protected', (req, res) => {
    res.send('Protected content');
  });
})();

在这里,我们创建了两个用户和两个权限。然后,我们为用户添加权限,并检查用户是否具备指定权限。最后,我们使用中间件检查用户权限。

总结

在本文中,我们介绍了如何使用 Sequelize 实现权限管理。我们首先设计了数据库,并定义了 User 和 Permission 两个模型。然后,我们在模型中定义了多对多关系,并在 User 模型中定义了 hasPermission() 方法。最后,我们使用中间件函数检查用户权限。通过本文的学习,你可以更好地掌握 Sequelize 的使用,以及如何在 Node.js 应用程序中实现权限管理。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/658d3e40eb4cecbf2d331c0a


纠错
反馈