User @ mdma描述了一些关于面向方面编程的内容。为此,您需要使用外部库(例如伟大的PostSharp),因为.NET没有太多的AOP功能。但是,。NET已经有了基于角色的安全的AOP机制,可以解决你的部分问题。看的标准.NET代码下面的例子:
[PrincipalPermission(SecurityAction.Demand, Role="HR")]
public List<Employees> GetAllEmployees()
{
// do stuff
}
的PrincipalPermissionAttribute是位于System.Security.Permissions命名空间的一部分,并且是.NET(因为.NET 1.0)的一部分。我已经使用它多年来已经在我的web应用程序中实现基于角色的安全性。关于这个属性的好处在于,.NET JIT编译器可以在后台为你编织所有内容,甚至可以在类级别上定义它。在这种情况下,该类型的所有成员都将继承该属性及其安全设置。
当然它有其局限性。您的第二个代码示例不能使用基于.NET角色的安全属性实现。我认为你不能真正围绕这种方法进行一些自定义安全检查,或者调用一些内部安全库。
public Order GetMyOrder(int orderId)
{
Order o = GetOrderInternal(orderId);
BusinessSecurity.ValidateOrderForCurrentUser(o);
}
当然你也可以使用一个AOP框架,但你仍然会写,这将再次拨打您自己的安全层的框架的具体属性。只有当这样一个属性可以代替多个方法调用时,这才会有用,例如当必须将代码放入try,catch,finally语句时。当你做一个简单的方法调用时,单个方法调用或单个属性IMO之间没有太大的区别。
当您返回对象的集合,并希望筛选出当前用户没有适当权限的所有对象,LINQ表达式树可以派上用场:
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和Entity Framework)支持LINQ,您可以编写一次这样的安全方法并将其应用到任何地方。当然,关于这一点的好处是,对数据库的查询总是最优的。换句话说,没有更多的记录将被检索超过需要。
UPDATE(年后):
我用这个属性在我的代码基础很长一段时间,但几年后,我来到了这个属性基于AOP有可怕的缺点的结论。例如,它阻碍了可测试性。由于安全代码是用普通代码编织的,因此无法运行正常的单元测试而无需模拟有效的用户。这是脆弱的,不应该成为单元测试的考虑因素(单元测试本身违反单一职责原则)。除此之外,它强制你用这个属性抛弃你的代码库。
因此,我宁愿用decorators来包装代码,而不是使用PrincipalPermissionAttribute
来代替安全性。这使得我的应用程序更加灵活并且更容易测试。在过去的几年中,我已经写了几篇关于这种技术的文章(例如this one和this one)。
我看到你已经在SO一段时间了。不过,我会建议您将标签([.net/c#])留在标题之外。让他们留在标签中。此外,“嗨”和“谢谢”虽然适合讨论论坛,但并不适用于SO等问答站点。谢谢。 – 2010-06-10 04:28:59
@John好的。感谢提示。 – gsharp 2010-06-10 06:30:25