2012-01-12 37 views
10

Dưới đây là yêu cầu của tôi:Tạo AuthorizeAttribute - tôi cần biết điều gì?

  • tôi sẽ được thêm người dùng đến lượng N vai trò; được định nghĩa trong cơ sở dữ liệu.

  • Tôi cần bảo vệ từng hành động của bộ điều khiển với thuộc tính ủy quyền của mình.

Ví dụ, ứng dụng web sẽ kiểm tra nếu đăng nhập người dùng thuộc về một trong hai vai trò này và nếu họ làm, tôi cho họ vào. Làm thế nào tôi có thể nói thuộc tính Authorize để lấy vai trò người dùng từ một bảng cơ sở dữ liệu tôi chọn?

[Authorize(Roles = "Admin, Technician")] 
public ActionResult Edit(int id) 
{ 
    return View(); 
} 

Tôi đã thử Googling cho nhiều trang khác nhau, nhưng dường như không phù hợp với những gì tôi cần và quá phức tạp.

Nếu số official documentation cũng có điều tôi muốn tìm, vì tôi không thấy bất kỳ điều gì tôi có thể sử dụng.

Mọi đề xuất?

Ví dụ: câu hỏi này có câu trả lời rất rõ ràng, nhưng tôi không biết nếu nó hoàn thành hoặc thiếu một cái gì đó quan trọng.

ASP.NET MVC3 Role and Permission Management -> With Runtime Permission Assignment


Sửa

Dường như những gì tôi đang thực sự tìm kiếm đang tạo ra một nhà cung cấp vai trò tùy chỉnh, có đúng không? Tôi có cần cần để triển khai lớp học này và sử dụng nó làm nhà cung cấp Vai trò của tôi không? Tôi khá mới ở đây, bất kỳ suy nghĩ?

http://msdn.microsoft.com/en-us/library/8fw7xh74.aspx

Trả lời

0

Có nhiều cách để xử lý việc này. Phương pháp và blowdarts của Darin (cả hai cá nhân rất có tay nghề cao - một trong số họ là một tác giả bảo mật) đều khá trong liên kết bạn cung cấp.

Một điều cần lưu ý là bộ nhớ cache. Nếu bạn sử dụng bộ nhớ đệm outputcache phía máy chủ, bạn có thể vô tình lưu vào bộ nhớ cache thứ gì đó cho một người dùng được trả lại cho người dùng khác. Xin vui lòng xem:

OutputCache and Authorize filters in MVC3

Why can't I combine [Authorize] and [OutputCache] attributes when using Azure cache (.NET MVC3 app)?

MVC Custom Authentication, Authorization, and Roles Implementation

để biết thêm về điều đó và làm thế nào để xử lý bộ nhớ đệm nếu bạn đang sử dụng một thuộc tính cho phép.

0

Bạn có thể sử dụng nhà cung cấp dịch vụ thành viên mặc định và nhà cung cấp vai trò, thay vì thực hiện riêng của bạn, nhưng bạn cũng sẽ cần phải sử dụng cơ sở dữ liệu thành viên asp.net mặc định, aspnetdb.mdf.

Xem here cho một hương

9

Tôi đã trải qua khá nhiều cùng một kịch bản quá khứ vài tuần vì vậy đây có thể giúp đỡ người khác trong cùng một thuyền. Kịch bản của tôi là một ứng dụng MVC4 trên mạng intranet của công ty với người dùng được lưu trữ trong Active Directory. Điều này cho phép xác thực Windows cho đăng nhập một lần, do đó không cần xác thực Mẫu. Vai trò được lưu trữ trong cơ sở dữ liệu Oracle. Tôi có 3 vai trò:

  • chỉ đọc: Tất cả người dùng cần phải là một thành viên của này để truy cập ứng dụng
  • User: Tạo resords mới
  • Admin: Chỉnh sửa và xóa các bản ghi

tôi quyết định sử dụng api nhà cung cấp vai trò asp.net để tạo AccountRoleProvider của riêng tôi. Cho đến nay tôi chỉ cần sử dụng 2 phương pháp trong này, GetRolesForUser và IsUserInRole:

public class AccountRoleProvider : RoleProvider // System.Web.Security.RoleProvider 
{ 
    private readonly IAccountRepository _accountRepository; 

    public AccountRoleProvider(IAccountRepository accountRepository) 
    { 
     this._accountRepository = accountRepository; 
    } 

    public AccountRoleProvider() : this (new AccountRepository()) 
    {} 

    public override string[] GetRolesForUser(string user521) 
    { 
     var userRoles = this._accountRepository.GetRoles(user521).ToArray(); 

     return userRoles; 
    } 

    public override bool IsUserInRole(string username, string roleName) 
    { 
     var userRoles = this.GetRolesForUser(username); 

     return Utils.IndexOfString(userRoles, roleName) >= 0; 
    } 
} 

tôi cập nhật web.config để sử dụng nhà cung cấp vai trò của tôi:

<authentication mode="Windows" /> 
<roleManager enabled="true" defaultProvider="AccountRoleProvider"> 
    <providers> 
    <clear/> 
    <add name="AccountRoleProvider" 
     type="MyApp.Infrastructure.AccountRoleProvider" /> 
    </providers> 
</roleManager> 

Sau đó, tôi tạo ra 2 tùy chỉnh các thuộc tính từ AuthorizeAttribute , ReadOnlyAuthorize và CustomAuthorize.

ReadonlyAuthorize:

public class ReadonlyAuthorize : AuthorizeAttribute 
{ 
    private IAccountRepository _accountRepository; 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var user = httpContext.User; 
     this._accountRepository = new AccountRepository(); 

     if (!user.Identity.IsAuthenticated) 
     { 
      return false; 
     } 

     // Get roles for current user 
     var roles = this._accountRepository.GetRoles(user.Identity.Name); 

     if (!roles.Contains("readonly")) 
     { 
      return false; 
     } 

     return base.AuthorizeCore(httpContext); 
    } 

    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     base.OnAuthorization(filterContext); 

     if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.Result is HttpUnauthorizedResult) 
     { 
      filterContext.Result = new ViewResult { ViewName = "AccessDenied" }; 
     } 
    } 
} 

CustomAuthorize:

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    public string RedirectActionName { get; set; } 
    public string RedirectControllerName { get; set; } 
    private IAccountRepository _accountRepository; 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var user = httpContext.User; 
     this._accountRepository = new AccountRepository(); 
     var accessAllowed = false; 

     // Get the roles passed in with the (Roles = "...") on the attribute 
     var allowedRoles = this.Roles.Split(','); 

     if (!user.Identity.IsAuthenticated) 
     { 
      return false; 
     } 

     // Get roles for current user 
     var roles = this._accountRepository.GetRoles(user.Identity.Name); 

     foreach (var allowedRole in allowedRoles) 
     { 
      if (roles.Contains(allowedRole)) 
      { 
       accessAllowed = true; 
      } 
     } 

     if (!accessAllowed) 
     { 
      return false; 
     } 

     return base.AuthorizeCore(httpContext); 
    } 

    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     base.OnAuthorization(filterContext); 

     if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.Result is HttpUnauthorizedResult) 
     { 
      var values = new RouteValueDictionary(new 
      { 
       action = this.RedirectActionName == string.Empty ? "AccessDenied" : this.RedirectActionName, 
       controller = this.RedirectControllerName == string.Empty ? "Home" : this.RedirectControllerName 
      }); 

      filterContext.Result = new RedirectToRouteResult(values); 
     } 
    } 
} 

Lý do cho 2 thuộc tính khác nhau là tôi sử dụng một cho vai trò chỉ đọc mà tất cả người dùng phải là thành viên của để truy cập ứng dụng. Tôi có thể thêm này trong phương pháp RegisterGlobalFilters trong Global.asax có nghĩa là nó được áp dụng tự động cho tất cả các Bộ điều khiển:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
{ 
    filters.Add(new HandleErrorAttribute()); 
    filters.Add(new ReadonlyAuthorize()); 
} 

Sau đó, trong CustomAuthorize tôi có thể tham gia một cách tiếp cận chi tiết hơn và xác định vai trò mà tôi muốn và áp dụng đối với một Bộ điều khiển hoặc một hành động cá nhân dưới đây, tôi có thể giới hạn truy cập vào các phương pháp Delete để người sử dụng trong vai trò quản lý:

[AccessDeniedAuthorize(RedirectActionName = "AccessDenied", RedirectControllerName = "Home", Roles = "Admin")] 
public ActionResult Delete(int id = 0) 
{ 
    var batch = myDBContext.Batches.Find(id); 
    if (batch == null) 
    { 
     return HttpNotFound(); 
    } 

    return View(batch); 
} 

Có những bước xa hơn tôi cần phải thực hiện như cập nhật các đối tượng người dùng với vai trò người sử dụng hiện nay là một thành viên của. Điều này sẽ lấy các vai trò cho Người dùng một lần thay vì mỗi lần trong các thuộc tính tùy chỉnh của tôi và cũng sử dụng User.IsInRole. Một cái gì đó như thế này nên có thể trong Application_AuthenticateRequest trong Gloal.asax:

var roles = "get roles for this user from respository"; 

if (Context.User != null) 
    Context.User = new GenericPrincipal(Context.User.Identity, roles); 
Các vấn đề liên quan