2010-02-23 29 views
52

Tôi là khu vực Quản trị và tôi chỉ muốn Quản trị viên nhập khu vực. Tôi đã xem xét việc thêm thuộc tính Authorized vào mọi controller trong vùng Admin. Không phải là có một giải pháp thanh lịch hoặc là tính năng này không có trong khung chính nó?Làm thế nào chúng ta có thể thiết lập ủy quyền cho toàn bộ một khu vực trong ASP.NET MVC?

EDIT: Tôi rất tiếc, tôi nên đề cập đến điều này trước đây. Tôi đang sử dụng một AuthorizedAttribute tùy chỉnh có nguồn gốc từ AuthorizeAttribute.

+0

Xem bài đăng trên blog của tôi [Đảm bảo ứng dụng ASP.NET MVC 3 của bạn] (http://blogs.msdn.com/b/rickandy/archive/2011/05/02/securing-your-asp-net-mvc- 3-application.aspx) – RickAndMSFT

+0

Xem bài đăng trên blog của tôi Đảm bảo ứng dụng ASP.NET MVC 4 của bạn và Thuộc tính AllowAnonymous mới – RickAndMSFT

+0

Liên kết cho nhận xét cuối cùng của Rick -> http://blogs.msdn.com/b/rickandy/archive/2012/ 03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx –

Trả lời

51

Web.config dựa trên an ninh nên hầu như không bao giờ được sử dụng trong một ứng dụng MVC. Lý do cho điều này là nhiều URL có khả năng có thể nhấn một bộ điều khiển, và đặt các kiểm tra trong Web.config luôn luôn bỏ lỡ một cái gì đó. Hãy nhớ - các bộ điều khiển không liên kết với các khu vực, các tuyến đường được kết hợp với các khu vực. Nhà máy điều khiển MVC sẽ vui vẻ phục vụ các bộ điều khiển từ các Vùng/thư mục cho các yêu cầu không thuộc khu vực nếu không có xung đột.

Ví dụ, sử dụng cấu trúc dự án mặc định, thêm vùng quản trị bằng AdminDefaultController, bạn có thể nhấn bộ điều khiển này qua/Admin/AdminDefault/Index /AdminDefault/Index.

Giải pháp được hỗ trợ duy nhất là đặt thuộc tính của bạn trên lớp cơ sở bộ điều khiển và để đảm bảo rằng mỗi bộ điều khiển trong khu vực phân lớp lớp cơ sở đó.

+0

Vâng, là một cách hay để chắc chắn một bộ điều khiển chỉ được nhấn qua một URL duy nhất? Bởi một kế hoạch chính xác của các tuyến đường có thể? –

+1

Không có cách nào để đảm bảo bộ điều khiển chỉ có thể truy cập thông qua một URL duy nhất. Các tuyến đường đơn giản là * một cơ chế * để truy cập các bộ điều khiển; chúng không phải là * cơ chế *. Đây là lý do tại sao bất kỳ thuộc tính bảo mật nào cần phải được áp dụng trực tiếp cho bộ điều khiển, chứ không phải cho các tuyến (và bằng cách mở rộng, các khu vực). Ví dụ, hãy xem xét việc giới thiệu của MvcHandler.ashx trong MVC 3. Điều này sẽ gọi vào khung MVC trực tiếp bằng cách bỏ qua * all * of Routing. – Levi

+0

Ok ... có nghĩa là không có câu trả lời đúng cho câu hỏi bên cạnh việc sử dụng chính xác các thuộc tính bảo mật? –

-5

.. rất thô lỗ Tôi tin rằng bạn muốn một cái gì đó như thế này?

Quick and dirty role management

[Authorize(Roles = "Admins")] 
public ActionResult Register() 
{ 
    ViewData["roleName"] = new SelectList(Roles.GetAllRoles(), "roleName"); 
    ViewData["PasswordLength"] = MembershipService.MinPasswordLength; 
    return View(); 
} 
+4

vui lòng đọc câu hỏi ... – icesar

13

Nếu tất cả các mã admin của bạn là trong một bộ điều khiển sau đó thêm Authorize cho toàn bộ lớp.

[Authorize] 
public class AdminController : Controller 
{ 
    ....... 
} 
+2

Điều đó hoạt động tốt cho một bộ điều khiển duy nhất. Nhưng làm thế nào để chúng tôi làm điều đó cho toàn bộ một khu vực? – ppumkin

42

Tôi vừa điều tra cùng một vấn đề này. Vì nó là không phải có thể để bảo đảm bộ điều khiển dựa trên các khu vực, một tùy chọn đơn giản hơn cần lưu ý.

Tạo định nghĩa bộ điều khiển cơ sở cho từng khu vực ghi đè Bộ điều khiển và thêm yêu cầu bảo mật cho điều này. Sau đó, bạn chỉ cần đảm bảo mỗi bộ điều khiển trong khu vực ghi đè AreaController thay vì Controller. Ví dụ:

/// <summary> 
/// Base controller for all Admin area 
/// </summary> 
[Authorize(Roles = "Admin")] 
public abstract class AdminController : Controller { } 

Nó vẫn yêu cầu bạn lấy mỗi bộ điều khiển trong lĩnh vực quản lý từ cơ sở này,

public class HomeController : AdminController 
{ 
    // .. actions 
} 

nhưng ít nhất bạn có một điểm duy nhất nơi bạn xác định sự an toàn cho khu vực này .

+2

Yea có vẻ giống như một ý tưởng hay. Bên cạnh đó MSDN đề xuất các giải pháp tương tự cho các vấn đề khác. Thừa kế là tốt. Tôi thích câu trả lời này. – ppumkin

+1

Tôi thực sự không hiểu tại sao bạn sẽ phân lớp mọi bộ điều khiển trong phần quản trị thay vì chỉ viết thuộc tính 1 dòng của bạn ở trên định nghĩa lớp. – Gudradain

+4

Câu trả lời đơn giản là DRY - http://en.wikipedia.org/wiki/Don't_repeat_yourself - tôi có thể thay đổi vai trò nào được bảo vệ trong một dòng mã, thay vì săn tìm từng thuộc tính [Authorize] – Quango

13

Tôi chỉ mới bắt đầu ... nhưng cho đến nay điều này đang hoạt động khá tốt đối với tôi.

Tôi tạo một lớp AuthorizeAttribute tùy chỉnh và thêm nó vào chức năng RegisterGlobalFilters.

Trong CustomAuthorizeAttribute tôi kiểm tra các điều kiện khác nhau dựa trên khu vực có trong đó.

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new CustomAuthorizeAttribute()); 
     filters.Add(new HandleErrorAttribute()); 
    } 
} 

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var routeData = httpContext.Request.RequestContext.RouteData; 
     var controller = routeData.GetRequiredString("controller"); 
     var action = routeData.GetRequiredString("action"); 
     var area = routeData.DataTokens["area"]; 
     var user = httpContext.User; 
     if (area != null && area.ToString() == "Customer") 
     { 
      if (!user.Identity.IsAuthenticated) 
       return false; 
     } 
     else if (area != null && area.ToString() == "Admin") 
     { 
      if (!user.Identity.IsAuthenticated) 
       return false; 
      if (!user.IsInRole("Admin")) 
       return false; 
     } 
     return true; 
    } 
} 
+0

cảm ơn. đây là cách tốt và lợi ích. –

0

Câu trả lời chấp nhận hiện nay không phải là giải pháp an toàn nhất vì nó đòi hỏi các nhà phát triển để luôn nhớ để thừa kế mà lớp cơ sở mới cho bất kỳ bộ điều khiển mới hoặc hành động ("danh sách đen"; cho phép người dùng truy cập vào tất cả mọi thứ trừ một hành động bị giới hạn theo cách thủ công). Điều này đặc biệt gây ra vấn đề khi các nhà phát triển mới, không quen thuộc với các nghi thức của bạn, được giới thiệu cho dự án. Thật dễ dàng để quên kế thừa các lớp điều khiển thích hợp nếu thực hiện theo cách đó, đặc biệt là sau khi đã rời mắt khỏi dự án trong nhiều tuần, vài tháng hoặc nhiều năm. Nếu một nhà phát triển quên kế thừa, nó không phải là rõ ràng rằng có một lỗ hổng bảo mật trong dự án.

Một giải pháp an toàn hơn cho vấn đề này là để từ chối truy cập vào tất cả yêu cầu, sau đó trang trí mỗi hành động với vai trò được phép truy cập vào các hành động ("danh sách trắng"; ngăn chặn truy cập đến tất cả người dùng trừ khi tự cho phép). Bây giờ nếu một nhà phát triển quên lập danh sách trắng cho phép phù hợp, người dùng sẽ cho bạn biết và nó đơn giản như nhìn vào các bộ điều khiển khác để được nhắc nhở về cách cung cấp quyền truy cập thích hợp. Tuy nhiên, ít nhất không có lỗ hổng bảo mật lớn.

Trong file App_Start/FilterConfig.cs, sửa đổi các lớp FilterConfig:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     ... 

     //Deny access to all controllers and actions so that only logged in Administrators can access them by default 
     filters.Add(new System.Web.Mvc.AuthorizeAttribute() { Roles = "Administrator" }); 
    } 

Điều này làm cho tất cả những hành động không thể tiếp cận trừ khi người dùng đang đăng nhập như một quản trị viên. Sau đó, đối với mỗi hành động mà bạn muốn người dùng được ủy quyền khác có quyền truy cập, bạn chỉ cần trang trí nó với [OverrideAuthorization][Authorize].

Trong logic nghiệp vụ của bạn, điều này cho phép bạn sử dụng thuộc tính Ủy quyền theo nhiều cách khác nhau mà không cần phải lo lắng về việc người dùng trái phép truy cập bất kỳ chức năng nào. Dưới đây là một số ví dụ.

Ví dụ 1 - Chỉ người dùng Quản trị viên và người điều phối đã đăng nhập mới được phép truy cập Index() Phương thức lấy và đăng.

public class MarkupCalculatorController : Controller //Just continue using the default Controller class. 
{ 
    // GET: MarkupCalculator 
    [OverrideAuthorization] 
    [Authorize(Roles = "Administrator,Dispatcher")] 
    public ActionResult Index() 
    { 
     //Business logic here. 

     return View(...); 
    } 

    // POST: DeliveryFeeCalculator 
    [HttpPost] 
    [ValidateAntiForgeryToken] 
    [OverrideAuthorization] 
    [Authorize(Roles = "Administrator,Dispatcher")] 
    public ActionResult Index([Bind(Include = "Price,MarkedupPrice")] MarkupCalculatorVM markupCalculatorVM) 
    { 
     //Business logic here. 

     return View(...); 
    } 
} 

Ví dụ 2 - Chỉ chứng thực người dùng sẽ được phép truy cập vào phương pháp điều khiển Trang chủ của Index().

public class HomeController : Controller 
{ 
    [OverrideAuthorization] 
    [Authorize] //Allow all authorized (logged in) users to use this action 
    public ActionResult Index() 
    { 
     return View(); 
    } 

} 

Ví dụ 3 - Những người dùng không (ví dụ: người dùng ẩn danh) có thể được phép phương pháp truy cập bằng cách sử dụng các thuộc tính [AllowAnonymous]. Điều này cũng tự động ghi đè bộ lọc chung mà không cần thuộc tính [OverrideAuthorization].

// GET: /Account/Login 
    [AllowAnonymous] 
    public ActionResult Login(string returnUrl) 
    { 
     ViewBag.ReturnUrl = returnUrl; 
     return View(); 
    } 

    // 
    // POST: /Account/Login 
    [HttpPost] 
    [AllowAnonymous] 
    [ValidateAntiForgeryToken] 
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) 
    { 
     ... 
    } 

Ví dụ 4 - Chỉ quản trị viên sẽ được phép tiếp cận với phương pháp mà thiếu thuộc tính [Authorize].

public class LocationsController : Controller 
{ 

    // GET: Locations 
    public ActionResult Index() 
    { 
     //Business logic here. 
     return View(...); 
    } 
} 

Một số lưu ý.

Bạn phải sử dụng thuộc tính [OverrideAuthorization] nếu bạn muốn giới hạn quyền truy cập vào một hành động cụ thể đối với các vai trò cụ thể. Nếu không, thuộc tính thuộc tính [Authorize] sẽ bị bỏ qua và chỉ vai trò mặc định (Quản trị viên trong ví dụ của tôi) sẽ được cho phép, ngay cả khi bạn chỉ định các vai trò khác (ví dụ: Người điều phối, v.v.) vì bộ lọc toàn cục. Bất kỳ người dùng trái phép nào đều sẽ được chuyển hướng đến màn hình đăng nhập.

Sử dụng thuộc tính [OverrideAuthorization] làm cho tác vụ bỏ qua bộ lọc chung mà bạn đã đặt. Do đó, bạn phải áp dụng lại thuộc tính [Authorize] bất cứ khi nào bạn sử dụng ghi đè để hành động vẫn an toàn.

Về toàn bộ khu vực và điều khiển

Để hạn chế bởi các khu vực, như bạn đang yêu cầu, đặt [OverrideAuthorization][Authorize] thuộc tính trên bộ điều khiển thay vì những hành động cá nhân.

Các vấn đề liên quan