Người dùng @mdma mô tả một chút về Lập trình hướng Aspect. Đối với điều này, bạn sẽ cần phải sử dụng một thư viện bên ngoài (chẳng hạn như PostSharp tuyệt vời), bởi vì .NET không có nhiều chức năng AOP. Tuy nhiên, .NET đã có một cơ chế AOP cho bảo mật dựa trên vai trò, có thể giải quyết một phần vấn đề của bạn. Hãy xem ví dụ sau đây của mã NET tiêu chuẩn:
[PrincipalPermission(SecurityAction.Demand, Role="HR")]
public List<Employees> GetAllEmployees()
{
// do stuff
}
Các PrincipalPermissionAttribute là một phần của không gian tên System.Security.Permissions và là một phần của .NET (kể từ NET 1.0). Tôi đã sử dụng nó trong nhiều năm nay để thực hiện bảo mật dựa trên vai trò trong các ứng dụng web của tôi. Điều tốt đẹp về thuộc tính này là trình biên dịch .NET JIT thực hiện tất cả việc dệt cho bạn trên nền và thậm chí bạn có thể định nghĩa nó trên một cấp lớp. Trong trường hợp đó tất cả các thành viên thuộc loại đó sẽ kế thừa thuộc tính đó và các thiết lập bảo mật của nó.
Tất nhiên nó có những hạn chế của nó. Không thể triển khai mẫu mã thứ hai của bạn bằng thuộc tính bảo mật dựa trên vai trò .NET. Tôi nghĩ bạn không thể thực sự tìm thấy một số kiểm tra bảo mật tùy chỉnh trong phương pháp này hoặc gọi một số thư viện bảo mật nội bộ.
public Order GetMyOrder(int orderId)
{
Order o = GetOrderInternal(orderId);
BusinessSecurity.ValidateOrderForCurrentUser(o);
}
Tất nhiên bạn có thể sử dụng khung công tác AOP nhưng bạn vẫn phải viết thuộc tính khung đặc biệt sẽ gọi lại lớp bảo mật của riêng bạn. Điều này sẽ chỉ hữu ích khi một thuộc tính như vậy sẽ thay thế nhiều cuộc gọi phương thức, ví dụ khi phải đặt mã bên trong try, catch, finally statements. Khi bạn thực hiện một cuộc gọi phương thức đơn giản, sẽ không có nhiều khác biệt giữa một cuộc gọi phương thức đơn lẻ hoặc một thuộc tính IMO duy nhất.
Khi bạn đang trở về một bộ sưu tập của các đối tượng và muốn lọc ra tất cả các đối tượng mà người sử dụng hiện nay không có quyền thích hợp, LINQ cây biểu thức có thể có ích:
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;
}
}
Khi O/RM hỗ trợ LINQ thông qua các cây biểu thức (như NHibernate, LINQ to SQL và Entity Framework), bạn có thể viết một phương thức bảo mật như vậy một lần và áp dụng nó ở mọi nơi. Tất nhiên điều tốt đẹp về điều này là, rằng truy vấn đến cơ sở dữ liệu của bạn sẽ luôn luôn được tối ưu. Nói cách khác, không có thêm hồ sơ sẽ được lấy ra hơn cần thiết.
UPDATE (năm sau):
tôi sử dụng thuộc tính này trong một thời gian dài trong cơ sở mã của tôi, nhưng vài năm trở lại, tôi đi đến kết luận rằng thuộc tính dựa AOP có nhược điểm khủng khiếp. Ví dụ, nó cản trở khả năng kiểm tra. Vì mã bảo mật được dệt bằng mã thông thường, bạn không thể chạy các kiểm tra đơn vị bình thường mà không phải mạo danh người dùng hợp lệ. Điều này là giòn và không phải là một mối quan tâm của các bài kiểm tra đơn vị (đơn vị kiểm tra chính nó vi phạm nguyên tắc trách nhiệm duy nhất). Bên cạnh đó, nó buộc bạn phải xả rác cơ sở mã của bạn với thuộc tính đó.
Vì vậy, thay vì sử dụng PrincipalPermissionAttribute
, tôi thay vì áp dụng các mối quan tâm chéo như bảo mật bằng mã gói với decorators. Điều này làm cho ứng dụng của tôi linh hoạt hơn và dễ kiểm tra hơn nhiều. Tôi đã viết một số bài viết về kỹ thuật này trong vài năm qua (ví dụ: this one và this one).
Tôi thấy bạn đã tham gia SO một thời gian. Tuy nhiên, tôi sẽ đề nghị bạn để thẻ ([.net/C#]) ra khỏi tiêu đề. Hãy để họ ở lại trong các thẻ. Ngoài ra, "Xin chào" và "Cảm ơn", trong khi thích hợp cho một diễn đàn thảo luận, không thích hợp cho một trang Hỏi & Đáp như SO. Cảm ơn. –
@John ok. Cảm ơn các gợi ý. – gsharp