【问题标题】:Document-Based Security in ASP.NET MVCASP.NET MVC 中基于文档的安全性
【发布时间】:2011-10-07 17:24:55
【问题描述】:

我已经了解 ASP.NET MVC 中基于用户和角色的安全性。但现在我需要一些更细化的东西。

假设我有一个文档列表,其中一些用户已获得授权,有些则没有。每个文档在数据库的文档表中都有对应的记录。如果用户具有安全访问权限,则可以下载文档以供查看。如果您有角色,也可以添加文档。每个文档都有一个 URL,每个文档列表都有一个 URL。

我想安全地修剪列表,以便用户只能看到他被授权的那些文档。但是我还需要对这些列表和文档的 URL 请求进行身份验证,因为没有什么可以阻止用户为他们不再有权访问的文档添加书签,或者只是在浏览器中输入 URL。

内置的基于角色的安全模型是否适合这种情况,或者我是否需要创建单独的基于表的安全性?我可以将安全性放在我的存储库中,以便返回的记录已经被修剪,还是应该是控制器的一部分?我是否需要一个安全属性来验证控制器请求,还是应该将其作为前几行代码放在控制器方法中?

【问题讨论】:

    标签: c# asp.net-mvc security access-control document-management


    【解决方案1】:

    @Robert,当你说你应该修剪它们(在它们到达视图之前)时,我想你已经回答了你自己的问题。因此,在您的业务逻辑中,作为对存储库的偏好,您可能想要做一个 lamda 来修剪多余的东西。

    我认为我永远不会将任何记录返回到不允许用户查看的视图中。为什么要增加风险和流量?

    至于书签,我认为您需要执行一些业务逻辑,以防止它们在访问不再存在时访问 url。

    我认为控制器只是为页面提供数据服务,没有任何逻辑,所以我更喜欢这个业务层方法,因为它看起来确实是一个业务规则。

    这可能不是您的想法,但除非有更好的方法,否则我会使用它。

    【讨论】:

    • 听起来您喜欢使用驻留在 DAL/ORM 的部分类中的业务逻辑的方法。听起来对吗?
    • 是的,但比这更独立。虽然我不介意,考虑到 DAL 中的部分想法,但我更喜欢的方法一直是将其外推到实际的业务层。当然,这一层将引用 DAL 对象,但它将我的业务逻辑与我的数据库分开。听起来访问权限是业务规则而不是 DAL 问题。
    • 我喜欢把它放在业务逻辑中的想法;您仍然可以对控制器隐藏安全检查,并且只需执行一次(它也适用于安全调整)。
    【解决方案2】:

    我将尝试解释我打算如何在我的项目中实现这一点。要求与您的要求相似:用户具有具有权限的角色,并且所有内容都可以从权限定义、角色的权限列表和用户的角色列表等中更改。因此,在某一时刻,用户可能有权访问某些内容,而在另一时刻,如果管理员更改某事,他无权访问。

    在我放一些代码之前,我会回答你的问题。

    我需要单独创建吗, 基于表的安全性?

    -是的

    我可以把安全放在我的 存储库,以便返回 记录已经被修剪,或者应该 它是控制器的一部分吗?

    -我认为安全性应该是业务逻辑的一部分,所以我会把它放在控制器和存储库之间。

    我需要一个安全属性来 验证控制器请求?

    -在我的项目中,我把它放在属性中,但有时我需要从控制器访问它,但由于我将安全逻辑保留在业务层中,我认为这不是问题。

    第一个属性是简单的属性,只允许登录用户执行操作:

    public class LoggedUserFilterAttribute : ActionFilterAttribute
    {
        public bool Logged { get; set; }
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (!SessionManager.IsUserLogged)
            {
                filterContext.Result = new RedirectToRouteResult(GetRedirectToNotLoggedRouteValues());
                this.Logged = false;
            }
            else
                this.Logged = true;
        }
    
        public RouteValueDictionary GetRedirectToNotAuthorizedRouteValues()
        {
            RouteValueDictionary routeValues = new RouteValueDictionary();
            routeValues.Add("action", "NotAuthorized");
            routeValues.Add("controller", "Authorization");
            return routeValues;
        }
        public RouteValueDictionary GetRedirectToNotLoggedRouteValues()
        {
            RouteValueDictionary routeValues = new RouteValueDictionary();
            routeValues.Add("action", "NotLogged");
            routeValues.Add("controller", "Authorization");
            return routeValues;
        }
    }
    

    然后我有,例如,只允许超级用户访问它的属性:

    public class SuperUserFilterAttribute : LoggedUserFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
    
            if (Logged)
            {
                MyBaseController controller = filterContext.Controller as MyBaseController;
                if (controller == null)
                    throw new Exception("Please use MyBaseController instead of built in Controller");
    
                User loggedUser = controller.Model.UserBO.GetUserByID(SessionManager.LoggedUser.UserID);
    
                if(!loggedUser.IsSuperUser)
                {
                    filterContext.Result = new RedirectToRouteResult(GetRedirectToNotAuthorizedRouteValues());
                }
            }
        }
    }
    

    MyBaseController 是继承 Controller 的类,并有一个 Model 类的实例,代表业务对象的容器。在控制器动作正文中,如果需要,我会检查当前实体的用户权限,并据此返回正确的视图:

        [LoggedUserFilter]
        public ActionResult LoadSomeEntity(int customerServiceID,int entityID)
        {
            UserRights userPermissionsView = Model.SecurityBO.GetUsersRightsOnEntity(SessionManager.LoggedUser.UserID, entityID);
    
            if(userPermissionsView.Write) 
                return View("EditEntity",Model.EntityBO.GetEntityByID(entityID));
            if(userPermissionsView.Read) 
                return View("ViewEntity",Model.EntityBO.GetEntityByID(entityID));
    
            return View("NotAuthorized");     
        }
    

    附言我不确定我是否可以向显然比我更有经验的人提出任何建议:),所以如果我发送垃圾邮件,我对此表示歉意。

    【讨论】:

    • 感谢您的回复。你有正确的想法;我已经看到了应用于用户和角色身份验证的属性模式。我看到其他人在这里发布了一个关于将属性用于基于表的安全性的问题。这种方法的问题是您需要访问 URL 参数才能正确执行此操作。由于该属性无法访问控制器方法的参数,因此您现在必须跳过一些环节才能获得它们。
    • 我明白了,OnAuthorize 方法中的 AuthorizeAttribute 无法访问控制器方法的参数,但我使用的 OnActionExecuting 中的 ActionFilterAttribute 可以:有 filterContext.ActionParameters 属性正在返回 IDictionary 其中key是参数名,value是传递给方法的值。
    • 这是一个很好的观察结果,但对于我的口味来说似乎有点太远了。因为无论如何我都要从我的模型中检索数据,所以我可以在那里安全地修剪它。如果用户无权访问某些记录,它们将根本不会出现在列表中,如果正在检索单个记录以获取详细信息视图,我可以检查 null 并重定向。
    • 完全同意你的看法。在我的项目中,业务逻辑并没有要求将这种细粒度的方法作为“记录级别的安全性”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-18
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多