在这篇博客中,我们将解释如何在node.js中实现基于角色的API授权。我们将在后端使用Express框架来实现一个基于角色的安全REST API。Node Express REST API的流程非常简单。每个REST API端点都受到认证和授权的限制。认证从用户模型中找到匹配的用户名和密码,而授权则看到匹配的角色,并对特定的REST API端点拥有权限。所以,用户、角色和权限模型的关系将是。
- 用户有一个或多个角色
- 每个安全端点都有一个基于角色的访问控制
因此,我们可以为特定的用户角色限制一些端点,并处理应用程序中的多个用户,同时保证端点和资源的可靠性。
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端点,使数据只对有权限访问该资源的特定角色的用户可用。
- 我们可以为多个用户重复使用相同的端点,并对其进行限制。

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