如何在不消耗它的情况下读取Vapor中间件中的参数

问题描述 投票:2回答:1

我是Vapor框架的新手,我正在努力保护多条路线。基本上,我想确保只有当用户实际访问具有该ID的特定广告系列时,才能访问/campaigns/:id下的所有路由。这样我就不能只在网址中输入任何ID并访问任何广告系列。

现在,我没有为每一条路线(目前已经是6条)添加逻辑,我认为我会使用中间件。这是我到目前为止所提出的,在Vapor Discord的一些友好人士的帮助下:

final class CampaignMiddleware: Middleware {
  func respond(to request: Request, chainingTo next: Responder) throws -> EventLoopFuture<Response> {
    let user = try request.requireAuthenticated(User.self)
    return try request.parameters.next(Campaign.self).flatMap(to: Response.self) { campaign in
      guard try campaign.userID == user.requireID() else {
        throw Abort(.forbidden, reason: "Campaign doesn't belong to you!")
      }
      return try next.respond(to: request)
    }
  }
}

struct CampaignController: RouteCollection {
  func boot(router: Router) throws {
    let route = router.grouped("campaigns")

    let tokenAuthMiddleware = User.tokenAuthMiddleware()
    let guardMiddleware = User.guardAuthMiddleware()
    let tokenAuthGroup = route.grouped(tokenAuthMiddleware, guardMiddleware)

    tokenAuthGroup.get(use: getAllHandler)
    tokenAuthGroup.post(CampaignCreateData.self, use: createHandler)

    // Everything under /campaigns/:id/*, CampaignMiddleware makes sure that the campaign actually belongs to you
    let campaignRoute = tokenAuthGroup.grouped(Campaign.parameter)
    let campaignMiddleware = CampaignMiddleware()
    let protectedCampaignRoute = campaignRoute.grouped(campaignMiddleware)

    protectedCampaignRoute.get(use: getOneHandler)
    protectedCampaignRoute.delete(use: deleteHandler)
    protectedCampaignRoute.put(use: updateHandler)

    // Add /campaigns/:id/entries routes
    let entryController = EntryController()
    try protectedCampaignRoute.register(collection: entryController)
  }

  func getAllHandler(_ req: Request) throws -> Future<[Campaign]> {
    let user = try req.requireAuthenticated(User.self)
    return try user.campaigns.query(on: req).all()
  }

  func getOneHandler(_ req: Request) throws -> Future<Campaign> {
    return try req.parameters.next(Campaign.self)
  }

  // ...deleted some other route handlers...
}

这里的问题是中间件通过做request.parameters.next(Campaign.self)“吞噬”竞选参数。所以在getOneHandler,它也试图访问req.parameters.next(Campaign.self),它失败并出现错误“参数不足”。这是有道理的,因为.next实际上从内部参数数组中删除了该参数。

现在,我如何编写一个使用该参数的中间件,而不是吃掉它?我是否需要使用原始值并自行查询Campaign模型?或者我可以在使用.next后以某种方式重置参数?或者还有另一种更好的方法来处理Vapor 3中的模型授权吗?

vapor server-side-swift
1个回答
3
投票

Heeey,看起来你可以从请求中得到你的Campaign,而不是像这样丢弃它

guard let parameter = req.parameters.values.first else {
    throw Abort(.forbidden)
}
try Campaign.resolveParameter(parameter.value, on: req)

所以你的最终代码可能看起来像

final class CampaignMiddleware: Middleware {
  func respond(to request: Request, chainingTo next: Responder) throws -> Future<Response> {
    let user = try request.requireAuthenticated(User.self)
    guard let parameter = request.parameters.values.first else {
        throw Abort(.forbidden)
    }
    return try Campaign.resolveParameter(parameter.value, on: request).flatMap { campaign in
      guard try campaign.userID == user.requireID() else {
        throw Abort(.forbidden, reason: "Campaign doesn't belong to you!")
      }
      return try next.respond(to: request)
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.