javascript - 如何在Plumier中创建基于用户权限的可重用自定义授权

标签 javascript node.js typescript plumier

我在创建可重复用于多个 Controller 的自定义授权时遇到问题。来自示例 here看起来自定义授权不能重用到另一个具有不同签名的 Controller 中。

在我的例子中,我有一些具有某些 Angular 色授权的端点,以防止未经授权的用户访问某些端点。

RoomsUsersController
POST /rooms/:roomId/users/:userId/kick    -> role: RoomAdmin
POST /rooms/:roomId/users/:userId/promote -> role: RoomAdmin
GET  /rooms/:roomId/users?offset&limit    -> role: RoomAdmin, RoomUser

只有 RoomAdmin 可以踢出和提升用户,并且只有注册的 RoomUserRoomAdmin 才能看到房间的用户列表。

我还创建了另一个由另一个 Controller 处理的速记端点,通过在帖子正文中提供 roomId 来踢和提升用户,如下所示。


UsersController
POST /users/:id/kick     body: {roomId}   -> role: RoomAdmin
POST /users/:id/promote  body: {roomId}   -> role: RoomAdmin

RoomsUsersControllerUsersController 的签名如下所示(方法主体和验证已删除)

@route.root("/rooms/:roomId/users")
export class RoomsUsersController {

    @route.post(":userId/kick")
    kick(roomId:string, userId:string){}

    @route.post(":userId/promote")
    promote(roomId:string, userId:string){}
}

export class UsersController {

    @route.post(":id/kick")
    kick(id: string, @bind.body() body: { roomId: string }) { }

    @route.post(":id/promote")
    promote(id: string, @bind.body() body: { roomId: string }) { }
}

我目前的解决方案是为 RoomsUsersControllerUsersController 创建不同的自定义授权,但它不那么干而且看起来很麻烦。

//custom authorization for RoomsUsersController
function roomUser(...roles: string[]) {
    return authorize.custom(async ({ user, parameters }) => {
        const room = await RoomModel.findById(parameters[0]).populate("users")
        const roomUser = room.users.find(x => x.userId === user.userId)
        if(!roomUser) throw new HttpStatusError(401, "Unauthorized user")
        return roles.some(x => x === roomUser.role)
    })
}

parameter[0] 不适用于 UsersController,因为它具有不同的签名。有人遇到同样的问题吗?

最佳答案

这是您需要的 route 属性。它包含有关当前 Controller/Action 处理请求的元数据信息。您可以使用 route.action.parameters 等获取当前操作参数元数据列表,其中包含参数名称、参数类型等,您可以查看完整架构 here .

您的 Controller 的问题是它们之间没有相似之处,无法检索自定义授权将使用的 roomId。您可以像下面这样修改您的 UsersController:

export class UsersController {

    @route.post(":id/kick")
    kick(id: string, roomId: string) { }

    @route.post(":id/promote")
    promote(id: string, roomId: string) { }
}

请注意,您可以将请求正文属性分解为多个参数。上面的代码显示之前的body: { roomId: string } 参数可以简化为roomId:string。如果 body 参数有更多属性,您可以简单地将它们分解为具有适当名称和类型的参数。

现在使用上面的 Controller ,UsersControllerRoomsUsersController 之间有相似之处,即 roomId 参数。您现在可以使用 route.action.parameters 访问它们,现在完整的自定义授权如下所示:

function roomUser(...roles: string[]) {
    return authorize.custom(async ({ user, route, parameters }) => {
        const index = route.action.parameters.findIndex(x => x.name === "roomId")
        if(index === -1) 
            throw new Error(`No parameter roomId found in 
 {route.controller.name}.${route.action.name}`)
        const room = await RoomModel.findById(parameters[index]).populate("users")
        const roomUser = room.users.find(x => x.userId === user.userId)
        if(!roomUser) throw new HttpStatusError(401, "Unauthorized user")
        return roles.some(x => x === roomUser.role)
    })
}

上面代码的想法是:你在 Action 参数中找到名为roomId的参数的位置,而不是从带有索引的parameters中获取值。

关于javascript - 如何在Plumier中创建基于用户权限的可重用自定义授权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58481395/

相关文章:

javascript - 2017 年 HTML/CSS 的实时重新加载/刷新解决方案

javascript - 如何在不上传文件的情况下使用 npm 的请求将文件发送到 Facebook Send API?

Typescript 类型,其中对象完全由一组可能属性的单个属性组成

typescript - 如何使用 Webpack、TypeScript 和 Sequelize

javascript - Java 属性文件到 JSON

javascript - 三J中使用正交相机时如何选择对象

node.js - Multer 模块无法启动

node.js - Sequelize.js 在创建实例时返回错误

node.js - 如何重新翻译其他网站的图像(隐藏源 URL)

typescript - 引用从 npm 类型导入的枚举时出错