【问题标题】:Where to place authorisation within an MVC web application?在 MVC Web 应用程序中的何处放置授权?
【发布时间】:2017-03-02 17:25:37
【问题描述】:

场景

您正在为您的营销部门构建一个 Web 应用程序。市场营销 部门已经要求一个博客平台,这样他们就可以留住你的客户 了解最新的公司新闻。你决定构建一个传统的 MVC 具有关系数据库的 Web 应用程序。您选择 LAMP(Linux Apache PHP MySQL) 堆栈或类似的。

营销团队的要求很简单。他们想要:

  • 营销团队的任何成员都可以创建博客文章
  • 任何人都可以阅读博客文章
  • 能够编辑博客文章的原作者或管理员
  • 能够删除博文的原作者或管理员
  • 任何人都可以列出所有博客文章

根据这些要求,您决定实施 RBAC(基于角色的访问 控制)。您将角色定义为:

  • 经理
  • 营销人员
  • 客人

您还创建了一个具有五个操作的“帖子控制器”:

  • 创建
  • 阅读
  • 更新
  • 删除
  • 列表

最后,您设置了一个身份验证系统。身份验证系统将 始终返回您实现的角色之一。如果用户已登录,则 您将获得“经理”或“营销人员”(取决于他们的工作 在您的公司内)。如果用户未登录,您将返回一个“Guest”。

在您开始实施授权之前,开发进展顺利 “更新”操作。

问题

该网站中“更新”操作的授权应该发生在哪里 申请?

确保不要混淆身份验证(检查用户是否已登录并 确定他们是谁)授权(检查用户是否允许 做他们想做的事)。

可能的答案

  1. 模型。

    • 由于无法查看原作者,无法进入动作 直到您调用模型为止。
    • 您的业务逻辑应该进入模型以坚持“瘦 控制器,胖模型”的经验法则。
    • 授权不应该发生在动作中,因为我们最终会 在调用相同模型的多个动作中复制我们的逻辑 方法。
  2. 动作。

    • 授权无法在模型中进行,因为并非所有操作都使用 模型。那么“创建”动作呢?它只能呈现 HTML 表单。 这意味着授权被跳过。
    • 将用户对象传递给每个模型方法似乎很麻烦。不是这样的 该操作是因为它知道用户所在的 HTTP 会话 已存储。
    • 当计划任务或 cronjob 运行时会发生什么? RBAC 在这里没有位置 除非我们实现“系统”角色。如果授权发生在 行动计划任务不需要知道角色。
    • 如果到模型的时候检查授权来不及怎么办 方法叫什么?被调用的方法可能是三个被调用的方法之一 一种行为。如果前两个通过,第三个失败,您可以介绍 您的 Web 应用程序的错误。预先进行所有授权检查 避免这种情况。
  3. 动作和模型。

    • 将授权拆分为“基于角色的身份验证”和 “业务逻辑身份验证”可能会起作用。但是你会在哪里画 线?
  4. 别处。

    • 我的 MVC Web 应用程序中是否缺少层?服务层或 中间件帮助在这里?

【问题讨论】:

    标签: model-view-controller web-applications architecture authorization


    【解决方案1】:

    根据我的经验,当您想到授权管理时,您必须经常考虑将 Aspect 理解为 AOP 范式(或类似的东西)的一个元素。因此,它位于所有应用程序层之上,但采用非侵入式方法。

    谈到授权管理应该放在哪里,我认为它必须放在一个公共的地方,你的“动作端点”将被调用和管理。例如,如果您有一个 rest 或 soap api,所有的授权管理都可以放在第一个请求处理程序中,以便在调用每个控制器操作之前拒绝未经授权的用户。

    回到一个简单的 3 层 MVC 应用程序,您可以定义一个在每个控制器操作之前调用的 AuthManager。 如果您的授权管理还涉及一些视图动态修改,则应使用不同且更具侵入性的方法,但这是一个不同的问题。

    【讨论】:

      【解决方案2】:

      经过大量搜索和研究,我想我找到了自己问题的答案。

      为了满足我需要实现“基于属性的访问控制”(缩写为ABAC)的要求。也称为“基于声明的访问控制”和“基于策略的访问控制”。

      ABAC 使用四个输入来决定是否允许当前用户做他们想做的事情。四个输入是:

      • 主题 - 这是用户对象。它将包含用户 ID 及其角色。
      • Action - 这将是控制器名称和操作名称。
      • 资源 - 这将是我给出的示例中的博客文章对象。
      • 环境 - 这可能会在我给出的示例中得到解决。但是您可以使用它来区分 Web 应用程序、API 或计划任务。

      检查应该发生在动作内部。这是一个快速的 PHP 伪代码示例:

      class PostsController {
          public function updateAction() {
              // get the post
              $model = new PostsModel();
              $post = $model->findById($_GET['id']);
              // check authorisation
              $authorised = $this->authorisor->check(
                  $this->user,
                  "PostsController::updateAction",
                  $post,
                  APP
              );
              // build response etc.
          }
      }
      

      为什么它需要在动作内部发生应该是显而易见的;没有其他资源(上例中的帖子)可以检查!

      【讨论】:

        猜你喜欢
        • 2015-03-03
        • 2021-12-04
        • 2015-02-28
        • 1970-01-01
        • 1970-01-01
        • 2011-06-24
        • 2013-10-01
        • 1970-01-01
        • 2013-10-07
        相关资源
        最近更新 更多