2010-04-27 22 views
20

Làm cách nào để tạo liên kết hành động "nhận thức bảo mật" phát hiện xem người dùng có được phép nhấp (gọi) hành động không?
Ẩn liên kết nếu dùng không được phép sử dụng hành động mà ...Liên kết hành động "Nhận thức bảo mật"?

Tùy thuộc từ

  • web.config (uỷ quyền) và
  • [Duyệt] thuộc tính vào các hành động

PS
Tôi đoán thực tiễn không tốt để kết hợp 2 trong MVC?

+1

Tôi đã kết hợp mã @ jfar với MvcSiteMapProvider để cung cấp hỗ trợ cho Khu vực. Nếu bất cứ ai quan tâm, tôi đã đặt những gì tôi có trên CodePlex tại https://authorizedactionlink.codeplex.com/. Nguồn và nhị phân .NET Framework 4.0 DLL có sẵn trên đó. – Bitmapped

Trả lời

30

Đây là một số mã được săn bắt từ dự án MvcSitemap và được sửa đổi để tôi sử dụng. Nếu tôi nhớ chính xác mã này đã được sửa đổi cho MVC2 và một số chức năng có thể phải được chuyển về MVC1.

Thực tiễn không tồi của nó để kết hợp MVC và FormsAuthentication cùng nhau, phương pháp xác thực mặc định của MVC được xây dựng xung quanh cơ sở hạ tầng bảo mật Asp.net hiện có.

Mã để xác định xem người dùng có quyền truy cập:

public static class SecurityTrimmingExtensions 
{ 

    public static bool HasActionPermission(this HtmlHelper htmlHelper, string actionName, string controllerName) 
    { 
     //if the controller name is empty the ASP.NET convention is: 
     //"we are linking to a different controller 
     ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName) 
               ? htmlHelper.ViewContext.Controller 
               : GetControllerByName(htmlHelper, controllerName); 

     var controllerContext = new ControllerContext(htmlHelper.ViewContext.RequestContext, controllerToLinkTo); 

     var controllerDescriptor = new ReflectedControllerDescriptor(controllerToLinkTo.GetType()); 

     var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName); 

     return ActionIsAuthorized(controllerContext, actionDescriptor); 
    } 


    private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 
    { 
     if (actionDescriptor == null) 
      return false; // action does not exist so say yes - should we authorise this?! 

     AuthorizationContext authContext = new AuthorizationContext(controllerContext); 

     // run each auth filter until on fails 
     // performance could be improved by some caching 
     foreach (IAuthorizationFilter authFilter in actionDescriptor.GetFilters().AuthorizationFilters) 
     { 
      authFilter.OnAuthorization(authContext); 

      if (authContext.Result != null) 
       return false; 
     } 

     return true; 
    } 

    private static ControllerBase GetControllerByName(HtmlHelper helper, string controllerName) 
    { 
     // Instantiate the controller and call Execute 
     IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory(); 

     IController controller = factory.CreateController(helper.ViewContext.RequestContext, controllerName); 

     if (controller == null) 
     { 
      throw new InvalidOperationException(

       String.Format(
        CultureInfo.CurrentUICulture, 
        "Controller factory {0} controller {1} returned null", 
        factory.GetType(), 
        controllerName)); 

     } 

     return (ControllerBase)controller; 
    } 

} 

Html Helpers

public static class SecurityTrimmedLink 
{ 
    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkName, string actionName) 
    { 
     return htmlHelper.HasActionPermission(actionName, "") 
        ? htmlHelper.ActionLink(linkName, actionName) 
        : MvcHtmlString.Create(""); 
    }   

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkName, string actionName, RouteValueDictionary routeValueDictionary) 
    { 
     return htmlHelper.HasActionPermission(actionName, "") 
        ? htmlHelper.ActionLink(linkName, actionName, routeValueDictionary) 
        : MvcHtmlString.Create(""); 
    } 

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkName, string actionName, object routeValues, object htmlAttributes) 
    { 
     return htmlHelper.HasActionPermission(actionName, "") 
        ? htmlHelper.ActionLink(linkName, actionName, routeValues, htmlAttributes) 
        : MvcHtmlString.Create(""); 
    } 

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkName, string actionName, string controllerName) 
    { 
     return htmlHelper.HasActionPermission(actionName, controllerName) 
        ? htmlHelper.ActionLink(linkName, actionName, controllerName) 
        : MvcHtmlString.Create(""); 
    } 

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkName, string actionName, string controllerName, object routeValues, object htmlAttributes) 
    { 
     return htmlHelper.HasActionPermission(actionName, controllerName) 
        ? htmlHelper.ActionLink(linkName, actionName, controllerName, routeValues, htmlAttributes) 
        : MvcHtmlString.Create(""); 
    } 
} 

Cảnh báo: Điều này sẽ không làm việc trong MVC 5 vì cuộc gọi đến FindAction() không bao giờ trả về một bộ mô tả hành động

Tôi đã cố gắng tìm ra vấn đề và không thể và kết thúc lập trình một công việc xung quanh. :(

+0

Ngọt ngào !!! Chính xác những gì tôi đang tìm kiếm! Cảm ơn! –

+0

Bạn có thể cập nhật câu trả lời này hoặc đăng câu trả lời mới, khi bạn triển khai bộ nhớ đệm như bạn đề cập trong nhận xét mã của mình không? :-) THANKS heaps ... Hoặc trỏ đến một blog hoặc tài nguyên để cập nhật thông tin này .. –

+0

@Peter Gfader Đây chỉ là một số mã nổi trên hộp công cụ cá nhân của tôi. Cho đến nay nó luôn là mối quan tâm hiệu suất nhỏ nhất. – jfar

2

Phần Diện tích phức tạp hơn một chút so với chỉ thêm một số quá tải. Các UseNamespaceFallback Hack không hoạt động bởi vì bạn sẽ nhanh chóng các sai khi bạn đã hệt tên điều khiển trong khu vực khác nhau.

Bạn cần để có một cách để có được không gian tên chính xác cho khu vực

khác này

IController controller = factory.CreateController(helper.ViewContext.RequestContext, controllerName); 

sẽ đi sai.

012.

Hiện nay tôi có các liên kết như thế này trong giao diện

@Html.SecurityTrimmedActionLink("this link", "Index", "Home",new {Area=string.Empty}); 
@Html.SecurityTrimmedActionLink("this link", "Index", "FunctionAdministration", new {Area="Administration" }, null); 

Bên

public static bool HasActionPermission(this HtmlHelper htmlHelper, string actionName, string controllerName, object area) 

tôi sẽ nhận được không gian tên cho khu vực hoặc không gian tên mặc định khi diện tích trống.

private static string GetNamespaceForArea(string area, RouteCollection routeColl) 
    { 
     string ns = string.Empty; 
     foreach (RouteBase routeBase in routeColl) 
     { 
      if (routeBase.GetType() == (typeof (Route))) 
      { 
       Route route = (Route) routeBase; 
       RouteValueDictionary dataTokens = route.DataTokens; 
       ; 
       if (area != null) 
       { 
        if (dataTokens.ContainsKey("area")) 
        { 
         if (area.Equals(dataTokens["area"])) 
         { 
          ns = (string) ((string[]) dataTokens["Namespaces"])[0]; 
          break; 
         } 
        } 
        else 
        { 
         if (area.Equals(string.Empty)) 
         { 
          ns = (string) ((string[]) dataTokens["Namespaces"])[0]; 
          break; 
         } 
        } 
       } 
      } 
     } 
     return ns; 
    } 

Bạn cần phải thiết lập không gian tên mặc định trong lộ trình của bạn trong globalasax ví dụ như thế này (ns mặc định "ActionLinkTest.Điều khiển "):

routes.MapRoute(
      "Default", // Route name 
      "{controller}/{action}/{id}", // URL with parameters 
      new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults 
      , new[] { "ActionLinkTest.Controllers" } 
     ); 

sử dụng nó để tạo ra bộ điều khiển dựa trên tên loại:

ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName) ? htmlHelper.ViewContext.Controller :(ControllerBase) Activator.CreateInstance(Type.GetType(type)); 

trong global.asax xác định các lĩnh vực đang

areaRegistration.Add("Administration","Areas.Administration"); 
6

jfar của làm việc cho tôi cho phần lớn, nhưng tôi phải thực hiện một số sửa đổi cho MVC4.Đây là phương pháp duy nhất phải thay đổi:

private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 
{ 
    if (actionDescriptor == null) 
     return false; // action does not exist so say yes - should we authorise this?! 

    AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor); 

    // run each auth filter until on fails 
    // performance could be improved by some caching 
    foreach (var filter in FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor)) 
    { 
     var authFilter = filter.Instance as IAuthorizationFilter; 

     if (authFilter == null) 
      continue; 

     authFilter.OnAuthorization(authContext); 

     if (authContext.Result != null) 
      return false; 
    } 

    return true; 
} 
Các vấn đề liên quan