2011-03-29 64 views
5

好吧,我想通過ActionLink方法爲我的網站添加一些安全性。如果用戶有足夠權限訪問動作/控制器,則ActionLink應呈現鏈接。如果沒有,它應該返回一個空字符串。現在,ActionLink是一個靜態方法,這使得它更加困難。有什麼方法可以實現我試圖做的事情嗎?如何覆蓋ActionLink行爲

+0

這不是很好的安全骯髒的工作。如果用戶能夠確定鏈接是什麼,他們可以直接輸入。隱藏鏈接可能是一件額外的事情,但您的真實安全應該發生在服務器上。 – 2011-03-29 18:15:55

+0

是的,我做到了,當它全部連接起來的時候真棒。我會挖掘一些代碼... – hunter 2011-03-29 18:16:17

+2

@Matt,如果正確完成,則不正確。您可以創建ActionLink,在完全呈現鏈接之前從類/方法查詢'Authorize'屬性。因此,您只需使用Authorize屬性即可控制鏈接的可見性並訪問該方法。 – hunter 2011-03-29 18:17:01

回答

8

AuthorizeActionLink擴展方法。根據需要超載。

public static MvcHtmlString AuthorizeActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes) 
{ 
    if (HasActionPermission(helper, actionName, controllerName)) 
     return helper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes); 

    return MvcHtmlString.Empty; 
} 

public static MvcHtmlString AuthorizeActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) 
{ 
    if (HasActionPermission(helper, actionName, controllerName)) 
     return helper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes); 

    return MvcHtmlString.Empty; 
} 

方法是做搞清楚,如果用戶被授權

static bool HasActionPermission(this HtmlHelper htmlHelper, string actionName, string controllerName) 
{ 
    ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName) 
     ? htmlHelper.ViewContext.Controller 
     : GetControllerByName(htmlHelper, controllerName); 

    ControllerContext controllerContext = new ControllerContext(htmlHelper.ViewContext.RequestContext, controllerToLinkTo); 
    ReflectedControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(controllerToLinkTo.GetType()); 
    ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName); 

    return ActionIsAuthorized(controllerContext, actionDescriptor); 
} 

static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 
{ 
    if (actionDescriptor == null) 
     return false; 

    AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor); 
    foreach (IAuthorizationFilter authFilter in actionDescriptor.GetFilters().AuthorizationFilters) 
    { 
     authFilter.OnAuthorization(authContext); 

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

    return true; 
} 

static ControllerBase GetControllerByName(HtmlHelper helper, string controllerName) 
{ 
    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; 
} 
+0

所以沒有辦法用相同的Html.ActionLink()方法來做到這一點? – 2011-03-29 18:26:59

+0

不,但我認爲這是一個偉大的可重用的方式來做這種類型的條件鏈接顯示在整個應用程序 – hunter 2011-03-29 18:43:40

+0

好吧:)然後:)謝謝 – 2011-03-29 18:59:26