MVC 3中的数据级安全性

时间:2011-10-11 18:38:09

标签: .net asp.net-mvc-3

我很好奇MVC 3中数据级安全性的最佳方法。让我画一幅画。

存在一个事件视图。此活动列出了活动的名称以及此活动中玩家正在播放的列表。

根据当前用户与该事件的关系,每个用户都会获得截然不同的视图。

例如,如果用户是管理器,则用户可以查看和管理该事件的所有其他用户可用性。

如果用户仅参与该事件,那么显然该用户只能操纵他自己的可用性。

有更多的组合。

我知道自定义操作过滤器,但这似乎有点过头了。

相反,我已经选择了一种方法,在事件索引上,有一个switch语句将重定向到相应的View,例如OrganiserEventView或PlayerEventView。

这很容易。我想。

它变得混乱的是我使用共享编辑器来枚举PlayerModels(主视图模型的一部分)来列出玩家。这个共享编辑器本身也必须尊重数据级安全性。

我是在正确的轨道上,还是有更好的方法?

4 个答案:

答案 0 :(得分:3)

邓肯,

这是我在每个应用程序中遇到的问题。以下是一些背景信息:我在大学的一个部门工作,因此我们必须处理多个数据源。我们的大多数应用程序都具有集成大学“中央IT”安全服务(如集中身份验证和活动目录)以及“自行开发”角色和权限的安全性。

我们的应用需要根据“自行开发”应用程序(在我们的部门内部使用)和企业数据中的数据,为不同用户提供不同的视图和操作。

我们的方法: 在环顾四周并且没有找到解决这个问题的好方法后,我最终编写了一个安全框架供我们使用。我不妨继续说明它在这里的作用。这是涉及的内容:

  1. 静态和动态角色。静态角色独立于数据(例如,我在应用程序中获得开发人员角色),而动态角色依赖于SecurityContext(例如,部门的财务官员在查看其部门的帐户时获得“财务官”角色。)
  2. 分配给静态或动态角色的权限。
  3. 一个SecurityContext,它封装了要执行权限检查所需的所有数据,包括当前用户和任何数据(例如帐号,提案文档ID,交易日期,任何内容)。
  4. SecurityContextValidator,它接受SecurityContext并返回对指定SecurityContext中指定用户有效的一组或多个角色。因此,决定谁可以看到本课程内容的逻辑。
  5. 每个SecurityContext一个SecurityContextValidator。使用SecurityContextManager在初始化时注册此映射。我使用Ninject加载我的安全模块,该模块在启动时执行此操作。
  6. 如果权限未指定SecurityContext,则使用默认上下文,SecurityContext仅包含Asp.Net安全性的Principal信息。
  7. 给予User,SecurityContext和Permission的SecurityService确定用户在该SecurityContext中具有的所有角色,并检查任何角色是否具有要检查的权限。
  8. 此时,这是Asp.Net MVC的示例流程:

    • 接收HttpRequest
    • 通过表单身份验证进行身份验证
    • 路由到控制器操作
    • if(Permission.GetByName(“CanDoSomething”)。IsAllowed()){// proceed

    - [Inside Permission.IsAllowed] -

    • SecurityService接收SecurityContext
    • 查找指定SecurityContext的SecurityContextValidator
    • 从SecurityContextValidator
    • 聚合所有静态和动态角色
    • 迭代角色并检查其中是否有任何人请求了权限。
    • 返回正确或错误!

    为了简化操作,我更进了一步,创建了一个AbstractContextProtectedAttribute,它需要一个可以创建SecurityContext的SecurityContextFactory委托(例如,给定一个HTTPRequest)和一个用指定的SecurityContext检查的权限。然后可以使用此类的子类来装饰控制器操作。

    唷!所以,让我现在设置一个用户,角色,权限表并将它们相互映射,定义数据库中的所有权限。我编写了一个可插入的SecurityPersistenceService,它使安全框架与所使用的持久性策略无关 - 我们遗憾地拥有从DataReaders,DataAdapters到Linq2Sql和EF的所有内容。但至少我们可以编写这样的代码:

    [Protected("CanAccessX")] // Checks using default context
    public class SomeController 
    {
        [Protected("CanSeeY")] // Checks using default context
        public PartialViewResult GetY(<parameters>) 
        {
            var canSeeY_Variation1 = Permission.Get("CanSeeY_Variation1") ;
            var y_Variation1_Context = new Y_Variation1_Context { <build your context here> } ;
            if (canSeeY_Variation1.IsAllowed(y_variation1_Context))
            {
                <return variation 1 view>
            }
    
            // Y_Variation_2...etc
        }
    }
    

    为了使这项工作,在启动时我注册了适当的验证器:

    public class MyNinjectModule
    {
        public override void Load()
        {
            // Wire up a persistence service for the security framework
            // to use.
            SecurityService.SecurityPersistenceService = new MySecurityPersistenceServiceImplementation() ;
    
            // This is what allows the SecurityService to figure out what Validator to use
            // in a specified Context to get the User's Roles.          
            SecurityService.RegisterValidator<Y_Variation1_Context>(new Y_Variation1_ContextValidator(...)) ;
        }
    }
    

    我现在正致力于增加这个框架,让我对数据的可枚举执行这些检查,从而将我的所有域对象注入安全基础结构。我知道这样做的唯一干净方法是使用AOP。我曾经在Java中工作并使用了AspectJ。现在我正在考虑PostSharp。

    希望这为思考你的问题提供了视角。

答案 1 :(得分:1)

答案将根据应用程序的大小,复杂程度和预计增长而变化。虽然在控制器中具有安全性然后具有不同的视图,但是存在权衡。例如,代码/标记复制可能是一个缺点。对于复杂的应用程序,portlet可能会有所帮助,但这很重要。视图可以根据安全性和访问角色进行更改,您可以像控制其他任何内容一样从控制器传递参数/数据(如果尚未通过会话提供)。我将为要使用的视图创建一个实用程序方法,以便逻辑/规则不会在视图中结束。

答案 2 :(得分:1)

我看到你的问题的方式,基于角色的安全性将是要走的路。

如果他们是组织者,那么他们就是组织者角色。但是你需要抽象一点。由于理论上组织者角色理论上是所有其他事件的组织者,因此您需要一种方法来做出此决定并根据请求填充角色,以便用户A是事件A的组织者,但不是事件B的组织者。这理想地需要在访问控制器代码之前发生,因此您的选择是global.asax.cs或auth过滤器。

答案 3 :(得分:0)

Using Roles and custom Role Attributes似乎非常适合(尽管我可以说没有代码或更好地理解您的代码库,没有人可以为您的问题提供“最佳”方式)。