帮助解决关于 ASP.NET MVC 和自定义安全设计的两部分问题

Posted

技术标签:

【中文标题】帮助解决关于 ASP.NET MVC 和自定义安全设计的两部分问题【英文标题】:Help with 2-part question on ASP.NET MVC and Custom Security Design 【发布时间】:2009-09-08 05:03:31 【问题描述】:

我正在使用 ASP.NET MVC,我正在尝试分离很多我的逻辑。最终,这个应用程序将非常大。它基本上是一个 SaaS 应用程序,我需要允许不同类型的客户端访问。我有一个两部分的问题;第一个处理我的一般设计,第二个处理如何在 ASP.NET MVC 中使用

首先,最初会有一个 ASP.NET MVC“客户端”前端,并且会有一组 Web 服务供第三方(可能是移动设备等)进行交互。

我意识到我可以让 ASP.NET MVC 应用程序仅通过 Web 服务进行交互,但我认为这是不必要的开销。

所以,我正在创建一个 API,它本质上是一个供 Web 应用程序和 Web 服务使用的 DLL。 API 由主要的业务逻辑集和数据传输对象等组成(因此,这包括 CreateCustomer、EditProduct 等方法)

另外,我的权限要求有点复杂。我不能真正使用直接的角色系统,因为我需要一些细粒度的权限(但所有权限都是积极的权限)。所以,我认为我不能真正使用 ASP.NET 角色/成员系统,或者如果可以的话,我似乎要做的工作比自己动手做更多。我以前使用过会员资格,对于这个我想我宁愿自己动手。

Web 应用程序和 Web 服务都需要关注安全性。所以,我的设计是这样的:

API 中的每个方法都需要验证调用者的安全性

在 Web 应用程序中,每个“页面”(MVC 中的“操作”)也会检查用户的权限(因此,如果用户没有,请不要向用户显示“添加客户”按钮有这个权利,但只要 API 收到 AddCustomer(),也要检查安全性)

我认为 Web 服务确实需要检查 DLL,因为它可能并不总是用于某种预先验证的上下文中(例如在 Web 应用程序中使用 Session/Cookies);在 API 中也有安全检查意味着如果我在移动设备上(比如 iPhone)并且不想对客户端进行各种检查,我真的不必在其他地方检查它

但是,在 Web 应用程序中,我认为会有一些重复的工作,因为 Web 应用程序会在向用户提供选项之前检查用户的安全性,这没关系,但我正在考虑一种方法来避免这种重复,方法是允许Web App 告诉 API 不检查安全性;而 Web 服务总是希望验证安全性

这是一个好方法吗?如果没有,有什么更好的?如果是这样,什么是实现这一点的好方法。我正在考虑这样做:

在 API 中,每个操作都有两个函数:

// Here, "Credential" objects are just something I made up
public void AddCustomer(string customerName, Credential credential
                           , bool checkSecurity)

  if(checkSecurity)
  
    if(Has_Rights_To_Add_Customer(credential)) // made up for clarity
    
      AddCustomer(customerName);
    
    else
      // throw an exception or somehow present an error
  
  else
    AddCustomer(customerName);


public void AddCustomer(string customerName)

  // actual logic to add the customer into the DB or whatever



  //  Would it be good for this method to verify that the caller is the Web App
  //  through some method? 

那么,这是一个好的设计还是我应该做一些不同的事情?


我的下一个问题是,显然我似乎不能真正使用 [Authorize ...] 来确定用户是否有权做某事。事实上,一项操作可能取决于多种权限,而视图可能会根据权限隐藏或显示某些选项。 最好的方法是什么?我是否应该有某种 PermissionSet 对象,用户在整个 Web 应用程序中携带 Session 或其他任何东西,MVC Action 方法将检查该用户是否可以使用该 Action,然后 View 将有一些 ViewData 或任何它检查各种隐藏/显示的权限?

【问题讨论】:

我建议你不要抛出异常。它们可能非常慢,并且会影响有效用户的性能。 @ChaosPandion,谢谢。我知道有人会提出来。我可能实际上会有某种 Result 对象,所有这些方法都会返回,但我不想陷入这些细节。这个问题够长了。 :) 【参考方案1】:

您的建议不会奏效。动作可以被缓存,当它们被缓存时,动作(以及你的家庭安全)不会运行。但是,ASP.NET 成员仍然有效,因为 MVC 缓存知道它.

您需要使用 ASP.NET 成员资格,而不是试图重新发明它。除其他外,您还可以:

实现自定义成员资格提供程序或角色提供程序。 子类型 AuthorizeAttribute 并重新实现 AuthorizeCore。 使用 Microsoft Geneva/Windows Identity Foundation 进行基于声明的访问。

另外,我完全不同意 ChaosPandion,他建议在分析之前对代码进行结构更改。出于“性能”原因而避免异常是荒谬的——尤其是仅仅可能为无效用户抛出异常的想法会以某种方式降低有效用户的性能。您的代码中最慢的部分可能在其他地方。使用分析器找出真正的性能问题,而不是追随最新的微“优化”时尚。

避免授权异常的正确原因是,在 Web 应用程序中指示未授权访问尝试的正确方法是将 HTTP 状态代码更改为 401 Unauthorized,而不是引发异常(这将返回 500)。

【讨论】:

可以禁用此缓存吗?如果您说的是真的,那么您似乎无法根据操作/视图中的权限进行任何隐藏/显示,因为它只会被缓存,因此也不会运行。因此,您在 ASP.NET MVC 中所能做的只是“您可以运行此操作方法还是不能?”此外,如果我的应用程序的其他部分(比如报告)总是只显示陈旧数据而不运行代码,那么这种缓存似乎有问题。对此有何建议?谢谢你的回答。 是的,您可以选择不缓存。但在这种情况下(试图促进从根本上破坏身份验证的方法),就像用斩首治疗痤疮(是的,它有效,但是......)。不,缓存确实意味着您不能对某个操作拥有权限,只是您建议的方式不起作用。如果您在现有身份验证中工作而不是尝试重新实现它,那么缓存和身份验证将携手并进。是的,不缓存的原因是陈旧的数据是不可接受的。这是特定于应用程序的,这就是默认情况下禁用缓存的原因。 另外,您可以将缓存设置为每个客户端工作,而不是在服务器上工作。这样,如果用户刷新(不运行安全性),用户将获得相同的权限,但是,如果另一个用户试图从另一台计算机访问该页面,服务器将为他提供一个新页面(从而再次运行安全性)。我仍然同意 Craig 的观点,您可能应该尝试使其与成员资格和角色系统一起使用。【参考方案2】:

将您的授权要求定义为域服务,以便它们可用于 Web 和 Web 服务实现。

使用授权过滤器在 Web 应用程序中执行您的授权检查,这应该像创建身份验证请求对象然后将其传递给您的身份验证域服务一样简单。

如果授权失败,则返回正确的错误 - Craig Stuntz 指出的 401。

始终授权该操作。如果您可以隐藏未经授权用户的链接 - 那很好。

通过编写 htmlHelper 扩展方法来简化您的视图/视图逻辑,该方法可以根据对 auth 域服务的调用显示/隐藏内容。

要从 Web 服务中使用您的授权服务,只需从通过服务消息传入的内容而不是从用户浏览器传递的 cookie 构造身份验证请求对象。

【讨论】:

以上是关于帮助解决关于 ASP.NET MVC 和自定义安全设计的两部分问题的主要内容,如果未能解决你的问题,请参考以下文章

七天学会ASP.NET MVC ——线程问题异常处理自定义URL

CORS 不工作 ASP.Net MVC5

关于linux asp.net MVC网站中 httpHandlers配置无效的处理方法

Asp.net MVC ModelState.Clear

ASP.NET MVC 4 帮助函数

ASP.NET MVC 表单身份验证 + 授权属性 + 简单角色