首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >确保业务层的方法安全。最佳实践/最佳模式

确保业务层的方法安全。最佳实践/最佳模式
EN

Stack Overflow用户
提问于 2010-06-09 23:34:03
回答 3查看 4.6K关注 0票数 9

我们使用ASP.NET和大量的AJAX“页面方法”调用。页面中定义的WebServices从我们的BusinessLayer中调用方法。为了防止黑客调用页面方法,我们希望在BusinessLayer中实现一些安全性。

我们正在与两个不同的问题作斗争。

第一个:

代码语言:javascript
复制
public List<Employees> GetAllEmployees()
{
    // do stuff
}

此方法应由具有"HR“角色的授权用户调用。

第二个:

代码语言:javascript
复制
public Order GetMyOrder(int orderId)
{
    // do sutff
}

此方法只能由订单的所有者调用。

我知道为每个方法实现安全性都很容易,如下所示:

代码语言:javascript
复制
public List<Employees> GetAllEmployees()
{
    // check if the user is in Role HR
}

代码语言:javascript
复制
public Order GetMyOrder(int orderId)
{
    // check if the order.Owner = user
}

我正在寻找的是一些模式/最佳实践,以一种通用的方式实现这种安全性(不需要每次都对if then else进行编码),我希望你能理解我的意思:-)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-06-16 18:43:03

User @mdma描述了一些面向方面的编程。为此,您需要使用一个外部库(比如强大的AOP ),因为.NET没有太多的PostSharp功能。但是,.NET已经为基于角色的安全性提供了一种面向方面的机制,可以部分解决您的问题。请看下面的标准.NET代码示例:

代码语言:javascript
复制
[PrincipalPermission(SecurityAction.Demand, Role="HR")]
public List<Employees> GetAllEmployees()
{
    // do stuff
}

PrincipalPermissionAttribute是System.Security.Permissions名称空间的一部分,也是.NET的一部分(从.NET 1.0开始)。我已经使用它多年来在我的web应用程序中实现基于角色的安全性。这个属性的好处是.NET即时编译器在后台为您完成了所有的编织工作,您甚至可以在类级别上定义它。在这种情况下,该类型的所有成员都将继承该属性及其安全设置。

当然,它也有其局限性。您的第二个代码示例不能使用.NET基于角色的安全属性来实现。我认为你不能在这个方法中进行一些自定义的安全检查,或者调用一些内部安全库。

代码语言:javascript
复制
public Order GetMyOrder(int orderId)
{
    Order o = GetOrderInternal(orderId);
    BusinessSecurity.ValidateOrderForCurrentUser(o);
}

当然,您可以使用AOP框架,但您仍然必须编写框架特定的属性,该属性将再次调用您自己的安全层。只有当这样的属性会替换多个方法调用时,这才有用,例如,当必须将代码放入try、catch、finally语句中时。当您要进行简单的方法调用时,单个方法调用和单个属性IMO之间没有太大区别。

当您返回一个对象集合,并且想要过滤掉当前用户没有适当权限的所有对象时,LINQ表达式树可以派上用场:

代码语言:javascript
复制
public Order[] GetAllOrders()
{
    IQueryable orders = GetAllOrdersInternal();
    orders = BusinessSecurity.ApplySecurityOnOrders(orders);
    return orders.ToArray();
}

static class BusinessSecurity
{
    public static IQueryable<Order> ApplySecurityOnOrders(
       IQueryable<Order> orders)
    {
        var user = Membership.GetCurrentUser();

        if (user.IsInRole("Administrator"))
        {
            return orders;
        }

        return 
            from order in orders
            where order.Customer.User.Name == user.Name
            select order; 
    }
}

当您的O/RM通过表达式树(如NHibernate、LINQ to SQL和实体框架)支持LINQ时,您可以编写一次这样的安全方法,然后将其应用到任何地方。当然,这样做的好处是,对数据库的查询总是最优的。换句话说,除非需要,否则不会检索更多记录。

更新(多年后):

我在我的代码库中使用了这个属性很长一段时间,但几年前,我得出结论,基于属性的AOP有可怕的缺点。例如,它阻碍了可测试性。由于安全代码是用普通代码编织而成的,因此如果不模拟有效用户,就无法运行普通单元测试。这是脆弱的,不应该成为单元测试的问题(单元测试本身违反了单一责任原则)。除此之外,它还会迫使您在代码库中使用该属性。

因此,我不使用PrincipalPermissionAttribute,而是通过用decorators包装代码来应用横切关注点,比如安全性。这使得我的应用程序更加灵活,测试起来也更加容易。在过去的几年里,我写了几篇关于这项技术的文章(例如this onethis one)。

票数 9
EN

Stack Overflow用户

发布于 2010-06-13 19:06:29

一个“最佳实践”是实现安全方面。这使安全规则与主要业务逻辑分离,避免了硬编码,并使在不同环境中更改安全规则变得容易。

下面的文章列出了实现方面和保持代码分离的7种方法。一种简单且不会更改业务逻辑接口的方法是使用代理。这将公开与您当前相同的接口,但允许另一种实现,它可以装饰现有的实现。可以使用硬编码或自定义属性将安全需求注入此接口。代理拦截对业务层的方法调用,并调用适当的安全检查。通过代理实现拦截在这里有详细描述-- Decouple Components by Injecting Custom Services into your Object's Invocation Chain。在Understanding AOP in .NET中给出了其他面向方面的方法。

下面是一个将安全性作为一个方面讨论的forum post,并使用通知和安全属性进行实现。最终结果是

代码语言:javascript
复制
public static class Roles 
{
    public const string ROLE_ADMIN = "Admin";
    public const string ROLE_CONTENT_MANAGER = "Content Manager";
}

// business method    
[Security(Roles.ROLE_HR)]
public List<Employee> GetAllEmployees();

您可以将属性直接放在您的业务方法上,紧密耦合,或者使用这些属性创建一个服务代理,以便将安全细节保持独立。

票数 2
EN

Stack Overflow用户

发布于 2010-06-10 12:20:23

如果您正在使用面向服务的体系结构,您可以创建一个Security Service,并且每个操作(方法)都将发送它的上下文(UserId、OrderId等)。安全服务了解业务安全规则。

方案可能是这样的

代码语言:javascript
复制
UI -> Security -> BLL -> DAL
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3007337

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档