2014-09-10 64 views
3

我想根據用戶的授權顯示/隱藏編輯/刪除鏈接(包括菜單項)。我已經實現了AuthorizeAttribute,併爲覆蓋AuthorizeCore的角色檢查定製邏輯。我想在檢查用戶是否有權查看LinkExtensions方法內的編輯/刪除鏈接時使用該邏輯。 這是我的設置:ASP.NET MVC 4自定義角色授權顯示/隱藏編輯/刪除視圖中的鏈接

public class AuthorizeActivity : AuthorizeAttribute 
{ 
    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     base.OnAuthorization(filterContext); 
    } 

    protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext) 
    { 
     bool isAuthorized = base.AuthorizeCore(httpContext); 
     string actionType = httpContext.Request.HttpMethod; 

     string controller = httpContext.Request.RequestContext.RouteData.Values["controller"].ToString(); 
     string action = httpContext.Request.RequestContext.RouteData.Values["action"].ToString(); 

     //ADMINS 
     if (controller == "Admin") 
     { 
      if (httpContext.User.IsInRole(Constants.Admin)) 
       return true; 
     } 
     else 
     { 
      //DATA READERS ONLY 
      if ((action == "Details") || (action == "Index")) 
      { 
       if (httpContext.User.IsInRole(Constants.DataReader)) 
        return true; 
      } 
      //DATA WRITERS & IT 
      else 
      { 
       ... 
      } 
     } 
     return false; 
    } 

而且我用費雯麗CHEVALLIER的邏輯創建授權的行動鏈路擴展這裏概述:http://vivien-chevallier.com/Articles/create-an-authorized-action-link-extension-for-aspnet-mvc-3 現在,在我看來,我可以使用:

<li>@Html.ActionLinkAuthorized("Admin", "Index", "Admin",false) </li> 

和鏈接要麼根據用戶權限顯示或不顯示。 在我的控制器的動作與裝飾:

[AuthorizeActivity] 
    public ActionResult Index() 
    { 
     return View(view); 
    } 

授權鏈接不會起作用,除非我也是,我認爲這是多餘的,像這樣的屬性指定「角色」:

[AuthorizeActivity(Roles = Constants.roleSalesContractAdmin)] 
public ActionResult Index() 
{ 
    return View(view); 
} 

我似乎無法找到重用AuthorizeAttribute中邏輯的方法。理想情況下,它將在ActionLinkAuthorized中被稱爲像Vivien's那樣:

public static MvcHtmlString ActionLinkAuthorized(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool showActionLinkAsDisabled) 
    { 
     if (htmlHelper.ActionAuthorized(actionName, controllerName)) //The call to verify here -- or inside ActionAuthorized 
     { 
      return htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes); 
     } 
     else 
     { 
      if (showActionLinkAsDisabled) 
      { 
       TagBuilder tagBuilder = new TagBuilder("span"); 
       tagBuilder.InnerHtml = linkText; 
       return MvcHtmlString.Create(tagBuilder.ToString()); 
      } 
      else 
      { 
       return MvcHtmlString.Empty; 
      } 
     } 
    } 

這是ActionAuthorized方法。當您裝飾一個動作或一個授權屬性的控制器OnAuthorization調用不會去定製一個

public static bool ActionAuthorized(this HtmlHelper htmlHelper, string actionName, string controllerName) 
    { 
     ControllerBase controllerBase = string.IsNullOrEmpty(controllerName) ? htmlHelper.ViewContext.Controller : htmlHelper.GetControllerByName(controllerName); 
     ControllerContext controllerContext = new ControllerContext(htmlHelper.ViewContext.RequestContext, controllerBase); 
     ControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(controllerContext.Controller.GetType()); 
     ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName); 

     if (actionDescriptor == null) 
      return false; 
     FilterInfo filters = new FilterInfo(FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor)); 

     AuthorizationContext authorizationContext = new AuthorizationContext(controllerContext, actionDescriptor); 
     foreach (IAuthorizationFilter authorizationFilter in filters.AuthorizationFilters) 
     { 
      authorizationFilter.OnAuthorization(authorizationContext); //This call 
      if (authorizationContext.Result != null) 
       return false; 
     } 
     return true; 
    } 
+0

你應該看看我的anwsear,可以給你一個想法:http://stackoverflow.com/questions/18874081/asp-net-mvc-alternatively-rendering-editorfor-based-on-user-role/18874497#18874497 – Fals 2014-09-10 18:56:02

+0

爲什麼不要將自定義授權屬性的AuthorizeCore中的邏輯提取爲靜態方法,將它放入某個靜態類並在屬性和助手中重用它? – 2014-09-10 19:02:39

回答

1

,當用戶被授權時,纔會執行該操作。這意味着如果用戶未被授權,視圖(將包含所有授權的鏈接擴展)將不會被渲染。

因此,您需要在您的屬性中的授權邏輯和您的html擴展的邏輯之間分開。

我還注意到,在您的屬性的授權核心你正在做以下幾點:

if ((action == "Details") || (action == "Index")) 
      { 
       if (httpContext.User.IsInRole(Constants.DataReader)) 
        return true; 
      } 

這是真的,非常糟糕的主意!您不應在您的授權核心邏輯中指定操作名稱! 所有你需要做的是裝飾「詳細信息」,並使用具有適當的角色默認授權屬性「指數」的方法:

[Authorize(Roles=Constants.DataReader)] 
public ActionResult Index() 
{ 
} 

現在關於角色依賴助手:

,你可以這樣做即:

public static MvcHtmlString ActionLinkAuthorized(this HtmlHelper htmlHelper, string roles, other arguments) 
{ 
    //assuming that roles are passed as coma separated strings 
    var rolesList = roles.Split(",",roles); 
    bool shouldShow = false; 
    foreach(var role in rolesList) 
    { 
     if (HttpContext.User.IsInRole(role)) 
     { 
      shouldShow = true; 
      break; 
     }    
    } 
    if(shouldShow) 
    { 
     //return your extension representation 
    } 
    else 
    { 
     //fallback 
    } 
} 
6

在你看來,你可以這樣寫:

@if (User.IsInRole("role")) 
{ 
    <li>@Html.ActionLink("Words", "View", "Controller")</li> 
    <li>@Html.ActionLink("Words", "View", "Controller")</li> 
} 

...並假設他們登錄,這將有條件地隱藏鏈接

0

我有一個類似的問題 我解決了這個辦法:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] 
    public class MyAuthorizedAttribute : AuthorizeAttribute 
    { 
     public bool CheckPermissions(HttpContextBase httpContext, string controller, string action) 
     { 
      bool authorized; 

      //Validate User permissions of the way you think is best 

      return authorized; 
     } 

     public override void OnAuthorization(AuthorizationContext filterContext) 
     { 
      var action = filterContext.ActionDescriptor.ActionName; 
      var controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; 
      if (filterContext == null) 
      { 
       throw new ArgumentNullException(nameof(filterContext)); 
      } 

      if (OutputCacheAttribute.IsChildActionCacheActive(filterContext)) 
      { 
       // If a child action cache block is active, we need to fail immediately, even if authorization 
       // would have succeeded. The reason is that there's no way to hook a callback to rerun 
       // authorization before the fragment is served from the cache, so we can't guarantee that this 
       // filter will be re-run on subsequent requests. 
       throw new InvalidOperationException("AuthorizeAttribute Cannot Use Within Child Action Cache"); 
      } 

      var skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof (AllowAnonymousAttribute), true) 
            || 
            filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(
             typeof (AllowAnonymousAttribute), true); 

      if (skipAuthorization) 
      { 
       return; 
      } 

      if (AuthorizeCore(filterContext.HttpContext) && CheckPermissions(filterContext.HttpContext, controller, action)) 
      { 
       // ** IMPORTANT ** 
       // Since we're performing authorization at the action level, the authorization code runs 
       // after the output caching module. In the worst case this could allow an authorized user 
       // to cause the page to be cached, then an unauthorized user would later be served the 
       // cached page. We work around this by telling proxies not to cache the sensitive page, 
       // then we hook our custom authorization code into the caching mechanism so that we have 
       // the final say on whether a page should be served from the cache. 

       var cachePolicy = filterContext.HttpContext.Response.Cache; 
       cachePolicy.SetProxyMaxAge(new TimeSpan(0)); 
       cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */); 
      } 
      else 
      { 
       HandleUnauthorizedRequest(filterContext); 
      } 
     } 

     private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus) 
     { 
      validationStatus = OnCacheAuthorization(new HttpContextWrapper(context)); 
     } 

     protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
     { 
      if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
      { 
       base.HandleUnauthorizedRequest(filterContext); 
      } 
      else 
      { 
       filterContext.Result = 
        new RedirectToRouteResult(
         new RouteValueDictionary(new {controller = "Error", action = "Unauthorized"})); 
      } 
     } 
    } 

這樣費雯麗CHEVALLIER的邏輯非常完美