学习Node.js基于角色的API授权

142 阅读4分钟

在这篇博客中,我们将解释如何在node.js中实现基于角色的API授权。我们将在后端使用Express框架来实现一个基于角色的安全REST API。Node Express REST API的流程非常简单。每个REST API端点都受到认证和授权的限制。认证从用户模型中找到匹配的用户名和密码,而授权则看到匹配的角色,并对特定的REST API端点拥有权限。所以,用户、角色和权限模型的关系将是。

  1. 用户有一个或多个角色
  2. 每个安全端点都有一个基于角色的访问控制

因此,我们可以为特定的用户角色限制一些端点,并处理应用程序中的多个用户,同时保证端点和资源的可靠性。

Node.js基于角色的API授权中间件的文件夹结构

首先,我们必须为node js项目的控制器、服务、模型、存储库和中间件保持一个适当的文件夹结构。

为用户角色和模型编写枚举

我们可以考虑在应用程序中有两种类型的用户:用户和管理员。因此,我们必须用枚举来声明两种角色。枚举的基本实现,我们可以定义一个对象来封装枚举类型,并为每个枚举值分配一个键。

import { model, Schema } from 'mongoose';

import lodash from 'lodash';

export enum Roles {

 USER = "USER",

 ADMIN = "ADMIN",

}

const userSchema: Schema = new Schema(

 {

   firstName: { type: String, required: false },

   lastName: { type: String, required: false },

   email: { type: String, required: false },

   avatar: { type: String, required: false },

   provider:{ type: String, required: false },

   providerId:{ type: String, required: false },

   roles:{

       type:[String],

       enum:Object.keys(Roles),

       default:Roles.USER

   }

 },


 {

   collection: 'users',

   timestamps: true

 },

);

const User = model('User', userSchema);

export default User;

为用户API访问端点编写控制器

当客户端点击API端点并被路由到我们Express应用程序的控制器时,我们需要添加一个用户和用户角色授权的中间件。在下面的片段中,你可以看到代码以及如何向授权中间件传递参数。

import express from "express";

import { Roles } from "../DB/Schemas/User";

const router = express.Router();

import userService  from './user.service';

import authorize from "./middlewares/authorize"

// routes

router.post('/authenticate', authenticate);     // public route

router.get('/users', authorize([Roles.ADMIN]), getAll); // admin only can see all users

router.get('/users/:id', authorize(), getById);       // all authenticated users pass empty or pass [Roles.USER,Roles.ADMIN]

module.exports = router;

function authenticate(req, res, next) {

   userService.authenticate(req.body)

       .then(user => user ? res.json(user) : res.status(400).json({ message: 'Username or password is incorrect' }))

       .catch(err => next(err));

}

function getAll(req, res, next) {

   userService.getAll()

       .then(users => res.json(users))

       .catch(err => next(err));

}

function getById(req, res, next) {

   const currentUser = req.user;

   const id = parseInt(req.params.id);

   userService.getById(id)

       .then(user => user ? res.json(user) : res.sendStatus(404))

       .catch(err => next(err));

编写授权角色中间件

这是一个重要的部分,是本博客的中心点。这将授权角色中间件函数接受参数,即我们从控制器路由传递给这个授权中间件函数的角色数组。

我们主要在这个中间件函数中提取该数组,并将从前端传来的JWT令牌解码为授权头。一旦我们解码了JWT令牌,我们就可以找到那个特定的用户对象和角色。

我们使用express-jwt模块,它自动从授权头中获取令牌并进行验证,并将用户对象附加到我们的请求对象上。

jwt({ secret, algorithms: ['HS256'] })

在这行代码之后,我们使用回调函数,如果令牌有效的话,我们就会得到请求对象,其中包含相关的req.user对象。在我们的用户模型中,我们已经定义了用户的角色,一个与该用户账户相关的角色数组。

因此,作为上述函数的输出,我们得到请求对象,如下所示

Request = { 

   body:{...},

   user: {

             …rest,

             roles:[ “ADMIN”]

             }

  }
Request = { 

   body:{...},

   user: {

             …rest,

             roles:[ “ADMIN”]

             }

  }

接下来,我们尝试将我们从req.user对象中得到的用户的角色和我们从函数参数中得到的角色进行匹配。如果角色被匹配,我们就调用nextFunction,这样它就能顺利地执行API路由栈中的下一个函数。如果Roles没有被匹配,那么我们就会显示一个状态401 Unauthorized错误,说 "这个资源对当前用户不可用"。

通过这种方式,我们可以在应用中管理多个用户角色的情况下保护路由,同时对不同用户角色的API端点进行访问控制。

Node.js基于角色的API授权的优势

  • 我们可以很容易地为每个用户类型区分API端点。
  • 我们可以保护API端点,使数据只对有权限访问该资源的特定角色的用户可用。
  • 我们可以为多个用户重复使用相同的端点,并对其进行限制。

coma

总结

在本教程中,我们了解了在Node.js中使用Express、Express-jwt和认证中间件实现基于角色的API授权。此外,我们还学习了如何在Express应用程序中根据用户角色限制API端点并确保API的安全。