卡住了创建"修剪安全性"的html.ActionLink扩展方法
时间:2020-03-06 14:35:57 来源:igfitidea点击:
我正在尝试为MVC的htmlHelper创建扩展方法。
目的是基于控制器/操作上设置的AuthorizeAttribute启用或者禁用ActionLink。
从MVCSitemap借用
Maarten Balliauw创建的代码,我想先确定用户对控制器/操作的权限,然后再决定如何呈现操作链接。
当我尝试获取MvcHandler时,我得到一个空值。
有没有更好的方法来设置控制器/动作的属性?
这是扩展方法的代码:
public static class HtmlHelperExtensions { public static string SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, string controller) { //simplified for brevity if (IsAccessibleToUser(action, controller)) { return htmlHelper.ActionLink(linkText, action,controller); } else { return String.Format("<span>{0}</span>",linkText); } } public static bool IsAccessibleToUser(string action, string controller) { HttpContext context = HttpContext.Current; MvcHandler handler = context.Handler as MvcHandler; IController verifyController = ControllerBuilder .Current .GetControllerFactory() .CreateController(handler.RequestContext, controller); object[] controllerAttributes = verifyController.GetType().GetCustomAttributes(typeof(AuthorizeAttribute), true); object[] actionAttributes = verifyController.GetType().GetMethod(action).GetCustomAttributes(typeof(AuthorizeAttribute), true); if (controllerAttributes.Length == 0 && actionAttributes.Length == 0) return true; IPrincipal principal = handler.RequestContext.HttpContext.User; string roles = ""; string users = ""; if (controllerAttributes.Length > 0) { AuthorizeAttribute attribute = controllerAttributes[0] as AuthorizeAttribute; roles += attribute.Roles; users += attribute.Users; } if (actionAttributes.Length > 0) { AuthorizeAttribute attribute = actionAttributes[0] as AuthorizeAttribute; roles += attribute.Roles; users += attribute.Users; } if (string.IsNullOrEmpty(roles) && string.IsNullOrEmpty(users) && principal.Identity.IsAuthenticated) return true; string[] roleArray = roles.Split(','); string[] usersArray = users.Split(','); foreach (string role in roleArray) { if (role != "*" && !principal.IsInRole(role)) return false; } foreach (string user in usersArray) { if (user != "*" && (principal.Identity.Name == "" || principal.Identity.Name != user)) return false; } return true; } }
解决方案
ViewPage引用了视图上下文,因此我们可以将其作为扩展方法。
然后,我们可以说是Request.IsAuthenticated还是Request.User.IsInRole(...)
用法将类似于" <%= this.SecurityLink(文本,demandRole,控制器,操作,值)%>"
这是工作代码:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Security.Principal; using System.Web.Routing; using System.Web.Mvc; using System.Collections; using System.Reflection; namespace System.Web.Mvc.Html { public static class HtmlHelperExtensions { public static string SecurityTrimmedActionLink( this HtmlHelper htmlHelper, string linkText, string action, string controller) { return SecurityTrimmedActionLink(htmlHelper, linkText, action, controller, false); } public static string SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, string controller, bool showDisabled) { if (IsAccessibleToUser(action, controller)) { return htmlHelper.ActionLink(linkText, action, controller); } else { return showDisabled ? String.Format("<span>{0}</span>", linkText) : ""; } } public static bool IsAccessibleToUser(string actionAuthorize, string controllerAuthorize) { Assembly assembly = Assembly.GetExecutingAssembly(); GetControllerType(controllerAuthorize); Type controllerType = GetControllerType(controllerAuthorize); var controller = (IController)Activator.CreateInstance(controllerType); ArrayList controllerAttributes = new ArrayList(controller.GetType().GetCustomAttributes(typeof(AuthorizeAttribute), true)); ArrayList actionAttributes = new ArrayList(); MethodInfo[] methods = controller.GetType().GetMethods(); foreach (MethodInfo method in methods) { object[] attributes = method.GetCustomAttributes(typeof(ActionNameAttribute), true); if ((attributes.Length == 0 && method.Name == actionAuthorize) || (attributes.Length > 0 && ((ActionNameAttribute)attributes[0]).Name == actionAuthorize)) { actionAttributes.AddRange(method.GetCustomAttributes(typeof(AuthorizeAttribute), true)); } } if (controllerAttributes.Count == 0 && actionAttributes.Count == 0) return true; IPrincipal principal = HttpContext.Current.User; string roles = ""; string users = ""; if (controllerAttributes.Count > 0) { AuthorizeAttribute attribute = controllerAttributes[0] as AuthorizeAttribute; roles += attribute.Roles; users += attribute.Users; } if (actionAttributes.Count > 0) { AuthorizeAttribute attribute = actionAttributes[0] as AuthorizeAttribute; roles += attribute.Roles; users += attribute.Users; } if (string.IsNullOrEmpty(roles) && string.IsNullOrEmpty(users) && principal.Identity.IsAuthenticated) return true; string[] roleArray = roles.Split(','); string[] usersArray = users.Split(','); foreach (string role in roleArray) { if (role == "*" || principal.IsInRole(role)) return true; } foreach (string user in usersArray) { if (user == "*" && (principal.Identity.Name == user)) return true; } return false; } public static Type GetControllerType(string controllerName) { Assembly assembly = Assembly.GetExecutingAssembly(); foreach (Type type in assembly.GetTypes()) { if (type.BaseType.Name == "Controller" && (type.Name.ToUpper() == (controllerName.ToUpper() + "Controller".ToUpper()))) { return type; } } return null; } } }
我不喜欢使用反射,但是无法进入ControllerTypeCache。