tl;dr:我的覆盖 AuthorizeAttribute 的 AuthorizeCore 方法的自定义属性未被正确调用 - 导致访问不受限制。
长话短说:我有一个具有四个角色(管理员、调度员、培训师和学生)的 ASP.NET MVC5 应用程序。直到现在我使用内置的
[Authorize("Administrator")]
我的 Controller ( View 和 API)的类和方法的属性,以针对按预期工作的 Active Directory 执行 Windows 身份验证。
现在我想更改属性中角色的硬编码字符串名称并从数据库中获取角色名称,这样就可以通过数据库配置 Active Directory 组名称,同时仍然执行身份验证直接针对 Active Directory。
工作流程:
- 方法/ Controller 仅允许角色“管理员”使用。
- 从数据库中获取“管理员”Active Directory 组,t.ex。 “域管理员”
- 检查当前用户是否是 Active Directory 组“DomainAdmins”的成员。如果是,授予访问权限。
我发现,Authorize 属性需要一个 const 值,所以我决定实现我的自定义
[DynamicAuthorize(Roles = Role.AdministratorRole)]
Role.AdministratorRole 是一个常量字符串。
现在我看到,对于 View Controller ,一切都按预期工作。但是当我的 API Controller 被调用时(例如删除用户),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();
}
}
}
基于:
- https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/AuthorizeAttribute.cs
- https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http/AuthorizeAttribute.cs
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
}
}
最佳答案
您需要为 API 在 System.Web.Http
中覆盖 AuthorizatioAttribute
上的 OnAuthorization
方法。
public virtual void OnAuthorization(HttpActionContext actionContext);
因此,Web API 的过滤器与 MVC 的过滤器不同。 Web API 过滤器位于 System.Web.Http.Filters 命名空间
关于c# - ASP.NET MVC5 自定义 AuthorizeAttribute 未被正确调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49687076/