【问题标题】:ASP.NET MVC5 custom AuthorizeAttribute not being invoked properlyASP.NET MVC5 自定义 AuthorizeAttribute 未正确调用
【发布时间】:2018-04-06 06:54:15
【问题描述】:

tl;dr:我的覆盖 AuthorizeAttribute 的 AuthorizeCore 方法的自定义属性没有被正确调用 - 导致访问不受限制。

长话短说:我有一个 ASP.NET MVC5 应用程序,它有四个角色(管理员、调度员、培训师和学生)。到目前为止,我使用的是内置的

[Authorize("Administrator")]

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

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

工作流程:

  1. 方法/控制器仅适用于“管理员”角色。
  2. 从数据库中获取“管理员”Active Directory 组,t.ex。 “域管理员”
  3. 检查当前用户是否是 Active Directory 组“DomainAdmins”的成员。如果是,请授予访问权限。

我发现 Authorize 属性需要一个 const 值,所以我决定实现我的自定义

[DynamicAuthorize(Roles = Role.AdministratorRole)]

Role.AdministratorRole 是一个常量字符串。

现在我看到,对于视图控制器,一切都按预期工作。但是当我的 API 控制器被调用(例如删除用户)时,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(不起作用 => 未被调用)

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(似乎正在工作 => 总是被调用)

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
    }
}

【问题讨论】:

  • web-api 的AuthorizeAttribute 位于System.Web.Http 命名空间中,并且与位于System.Web.Mvc 命名空间(您正在使用的那个)中的mvc 的AuthorizeAttribute 不兼容
  • 谢谢,确实是这个问题!我在问题中添加了我的解决方案。
  • 问题中没有答案(我已回滚您的更改)
  • 哦,抱歉,我刚刚重新编辑并想知道为什么更改会还原。我应该发帖回答新帖子吗?
  • 这是一个问答网站。再次回答(解决方案)不要进入问题。我再次回滚了您的更改。如果您想发布自己的答案,请随时这样做。

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


【解决方案1】:

您需要覆盖 AuthorizatioAttribute 上的 OnAuthorization 方法,该方法可用于 API 的 System.Web.Http

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/

【讨论】:

  • 感谢您指出这一点并链接文章。考虑到这一点,我让它工作了。最后我覆盖了IsAuthorized(...) 方法。我编辑了我的问题并添加了答案。
【解决方案2】:

解决方案: 正如所指出的,问题在于 MVC 和 HTTP 控制器实际上使用了不同的实现。因此我的AuthorizeCore(...) 从未被调用过。解决方案是创建另一个属性(所以我有DynamicAuthorizeMvcDynamicAuthorizeHttp)从System.Web.Http 命名空间实现AuthorizeAttribute。我不得不重写方法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();
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-17
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多