Stuck creating a “security trimmed” html.ActionLink extension method

后端 未结 3 848
难免孤独
难免孤独 2021-01-06 08:08

I\'m trying to create an Extension Method for MVC\'s htmlHelper. The purpose is to enable or disable an ActionLink based on the AuthorizeAttribute set on the controller/acti

3条回答
  •  悲&欢浪女
    2021-01-06 08:53

    Here is the working code:

    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("{0}", 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;
            }
        }
    }
    

    I don't like using reflection, but I can't get to the ControllerTypeCache.

提交回复
热议问题