Asp.net-Mvc
ASP.Net MVC如何判斷一個使用者是否可以訪問一個URL?
因此,當您有使用者登錄時,我正在閱讀有關登錄循環的另一個問題,設置為返回登錄後他們可能無法訪問的 URL(即管理頁面,並且使用者使用普通帳戶登錄) .
WebForms 下的解決方案似乎是利用該
UrlAuthorizationModule.CheckUrlAccessForPrincipal方法。但是,這不適用於使用授權屬性保護的操作方法的 URL。我想我可以找出 URL 指向的方法並對其進行反思以解決我的問題 - 但我似乎無法弄清楚如何從路由表中獲取這些資訊。有人曾經使用過這個,或者有解決方案嗎?如果我能從一個 URL 中獲取路由資訊,我想我可以解決剩下的問題,但如果有人有一個通用的解決方案 - 即。一些類似於前面提到的用於 MVC 的隱藏方法,那也將非常棒。
我不是在問如何檢查 User 是否有權訪問指定的 Controller/Action pair。我首先需要弄清楚如何根據 URL 從 RouteTable 中獲取 Controller/Action 對。所有背景故事的原因是,如果確實存在
UrlAuthorizationModule.CheckUrlAccessForPrincipalMVC 的等價物。
為 MVC 4 更新了 John Farrell (jfar) 的答案(SecurityTrimmingExtensions 類):
public static class SecurityCheck { public static bool ActionIsAuthorized(string actionName, string controllerName) { IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory(); ControllerBase controller = factory.CreateController(HttpContext.Current.Request.RequestContext, controllerName) as ControllerBase; var controllerContext = new ControllerContext(HttpContext.Current.Request.RequestContext, controller); var controllerDescriptor = new ReflectedControllerDescriptor(controller.GetType()); var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName); AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor); foreach (var authAttribute in actionDescriptor.GetFilterAttributes(true).Where(a => a is AuthorizeAttribute).Select(a => a as AuthorizeAttribute)) { authAttribute.OnAuthorization(authContext); if (authContext.Result != null) return false; } return true; } }
我從 MvcSitemap 移植並破解了這段程式碼:
public static class SecurityTrimmingExtensions { /// <summary> /// Returns true if a specific controller action exists and /// the user has the ability to access it. /// </summary> /// <param name="htmlHelper"></param> /// <param name="actionName"></param> /// <param name="controllerName"></param> /// <returns></returns> 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; }它可以使用一些記憶體,但對我來說這是一個過早的優化。