ASP.NET MVC5自定义AuthorizeAttribute未正确调用

时间:2018-04-06 06:54:15

标签: c# asp.net asp.net-mvc asp.net-mvc-5

 

tl; dr:我的自定义属性覆盖了AuthorizeAttribute的AuthorizeCore方法未正确调用 - 导致无限制访问。

长篇故事:我有一个ASP.NET MVC5应用程序,有四个角色(管理员,调度程序,培训师和学生)。到现在为止我使用了内置的

[Authorize("Administrator")]

对我的控制器(View和API)的类和方法的属性,以针对按预期工作的Active Directory执行Windows身份验证。

现在,我想更改属性中角色的硬编码字符串名称,并从数据库中获取角色名称,以便可以通过数据库配置Active Directory组名称,同时仍然执行身份验证直接针对Active Directory。

工作流:

  1. 方法/控制器允许角色"管理员"仅
  2. 获取"管理员"来自数据库的Active Directory组,t.ex。 " DomainAdmins"
  3. 检查当前用户是否是Active Directory组" DomainAdmins"的成员。如果是,请授予访问权限。
  4. 我发现,Authorize属性需要一个const值,所以我决定实现自定义

    [DynamicAuthorize(Roles = Role.AdministratorRole)]
    

    Role.AdministratorRole是一个const字符串。

    现在我看到,对于视图控制器,一切都按预期工作。但是当我的API控制器被调用时(t.ex。删除用户),AuthorizeCore(...)方法被而不是被调用。

    可能与线程安全或ASP.NET MVC5如何在内部工作有关。我还认为AuthorizeCore(...)方法中的代码并不重要,因为它甚至没有被调用。

    我很感激任何提示或建议。

    DynamicAuthorize.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Principal;
    using System.Web;
    using System.Web.Mvc;
    
    namespace Project.Utilities.Attributes
    {
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
        public class DynamicAuthorize : AuthorizeAttribute
        {
            protected override bool AuthorizeCore(HttpContextBase httpContext)
            {
                if (httpContext == null)
                {
                    throw new ArgumentNullException("httpContext");
                }
    
                IPrincipal user = httpContext.User;
                if (!user.Identity.IsAuthenticated)
                {
                    return false;
                }
    
                if (SplitString(Users).Length > 0 && !(SplitString(Users).Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase)))
                {
                    return false;
                }
    
                // Role preparation
                List<string> allowedRolesRaw = new List<string>(SplitString(Roles));
                string allowedRolesAd = "";
    
                // GetRolesActiveDirectoryGroupName(...) loads role names from the database
                allowedRolesRaw.ForEach(rc => allowedRolesAd += DomainMapper.GetRolesActiveDirectoryGroupName(DomainMapper.GetRoleIdFromAttributeName(rc), true) + ", ");
    
                if (SplitString(Roles).Length > 0 && !(SplitString(allowedRolesAd).Any(user.IsInRole)))
                {
                    return false;
                }
    
                return true;
            }
    
            internal static string[] SplitString(string original)
            {
                if (String.IsNullOrEmpty(original))
                {
                    return new string[0];
                }
    
                var split = from piece in original.Split(',')
                            let trimmed = piece.Trim()
                            where !String.IsNullOrEmpty(trimmed)
                            select trimmed;
                return split.ToArray();
            }
        }
    }
    

    基于:

    UsersController.cs (不工作=&gt;未被调用)

    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
    using System.Web.Http;
    using System.Web.Http.Description;
    using Project.Models;
    using Project.Utilities.Attributes;
    
    namespace Project.Controllers.api
    {
        [DynamicAuthorize(Roles = Role.AdministratorRole)]
        public class UsersController : ApiController
        {
            // Methods in here do not have an attribute
        }
    }
    

    ManagementController.cs (似乎工作=&gt;始终被调用)

    using Project.Utilities.Attributes;
    using Hangfire;
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Net;
    using System.Web.Mvc;
    using static Project.Utilities.Attributes.AntiForgeryToken;
    using Project.Dtos;
    using Project.Mapper;
    using Project.ViewModels;
    using System.ComponentModel.DataAnnotations;
    using System.Text.RegularExpressions;
    
    namespace Project.Controllers
    {
        [DynamicAuthorize(Roles = Role.AdministratorRole + ", " + Role.SchedulerRole)]
        public class ManagementController : Controller
        {
            // Methods here do sometimes have an attribute if a specific action is also allowed for different roles
        }
    }
    

2 个答案:

答案 0 :(得分:1)

您需要覆盖OnAuthorizationAuthorizatioAttribute for System.Web.Http的{​​{1}}方法。

public virtual void OnAuthorization(HttpActionContext actionContext);

因此, Web API的过滤器与MVC的过滤器不同。 Web API过滤器位于System.Web.Http.Filters命名空间

您可以获得更多详细信息https://damienbod.com/2014/01/04/web-api-2-using-actionfilterattribute-overrideactionfiltersattribute-and-ioc-injection/

答案 1 :(得分:0)

<强>解决方案: 正如所指出的那样,问题是MVC和HTTP控制器实际上使用了不同的实现。因此我的AuthorizeCore(...)从未被召唤过。解决方案是创建另一个属性(我有DynamicAuthorizeMvcDynamicAuthorizeHttp)从AuthorizeAttribute命名空间实现System.Web.Http。我不得不重写方法protected override bool IsAuthorized(HttpActionContext actionContext)。然后我将DynamicAuthorizeMvc用于MVC控制器,将DynamicAuthorizeHttp用于API控制器。工人阶级之后:

<强> DynamicAuthorizeHttp.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Web.Http;
using System.Web.Http.Controllers;

namespace Project.Utilities.Attributes
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class DynamicAuthorizeHttp : AuthorizeAttribute
    {
        protected override bool IsAuthorized(HttpActionContext actionContext)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException("actionContext");
            }

            IPrincipal user = actionContext.ControllerContext.RequestContext.Principal;
            if (user == null || user.Identity == null || !user.Identity.IsAuthenticated)
            {
                return false;
            }

            if (SplitString(Users).Length > 0 && !(SplitString(Users).Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase)))
            {
                return false;
            }

            // Role preparation
            List<string> allowedRolesRaw = new List<string>(SplitString(Roles));
            string allowedRolesAd = "";

            allowedRolesRaw.ForEach(rc => allowedRolesAd += DomainMapper.GetRolesActiveDirectoryGroupName(DomainMapper.GetRoleIdFromAttributeName(rc), true) + ", ");


            if (SplitString(Roles).Length > 0 && !(SplitString(allowedRolesAd).Any(user.IsInRole)))
            {
                return false;
            }

            return true;
        }

        internal static string[] SplitString(string original)
        {
            if (String.IsNullOrEmpty(original))
            {
                return new string[0];
            }

            var split = from piece in original.Split(',')
                        let trimmed = piece.Trim()
                        where !String.IsNullOrEmpty(trimmed)
                        select trimmed;
            return split.ToArray();
        }
    }
}
相关问题