gpt4 book ai didi

asp.net-mvc - ASP.NET Core 中基于事件的授权

转载 作者:行者123 更新时间:2023-12-04 07:16:31 25 4
gpt4 key购买 nike

我们有一个 asp.net mvc 应用程序,我将其移植到 aspnet core mvc。
在旧的解决方案中,身份验证是使用 Windows 身份验证完成的。

最重要的是,我们有一个“基于事件的身份验证”(如 http://ryankirkman.com/2013/01/31/activity-based-authorization.html );用户与角色相关联,而角色与权限相关联。用户角色和相应的权限存储在一个单独的应用程序中,该应用程序作为我们的应用程序和少数其他系统的授权服务。

向授权服务 api 查询用户“Jon Doe”的权限将得到如下响应:

{
Email:"Jon.Doe@acme.com",
FirstName:"Jon",
LastName:"Doe",
Resources:
[
"CanAccessWebApplication",
"CanCopyAppointment",
"CanEditAppointment",
"CanEditContact",
"CanSaveContact"
...
]
Alias:"1234567",
UserId:"1234"
}

在我们当前的应用程序中,这些权限是使用 Controller 方法上的属性(我们自己实现的)检查的:
public ContactController
{
[ActionUserAccess("CanSaveContact")]
public ActionResult SaveContact
{
...
}
}
ActionUserAccessAttribute 过滤器的当前遗留实现如下所示:
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public sealed class ActionUserAccessAttribute : ActionFilterAttribute
{
private readonly string _accessRight;

public ActionUserAccessAttribute(string accessRight)
{
_accessRight = accessRight;
}

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
throw new InvalidOperationException("ActionUserAccessAttribute can not be used for controllers or actions configured for anonymous access");
}

base.OnActionExecuting(filterContext);

var securityService = ContainerResolver.Container.GetInstance<ISecurityService>();
var hasResource = securityService.HasAccess(_accessRight);

if (!hasResource)
{
filterContext.Result =
new HttpStatusCodeResult(
403,
string.Format(
"User {0} is not authorized to access the resource:'{1}' ",
filterContext.HttpContext.User.Identity.Name,
_accessRight));
}
}
}
}

将属性/过滤器移植到 aspnetcore 似乎很简单,但根据“asp.net 安全人员”@blowdart 的这个答案 https://stackoverflow.com/a/31465227/1257728 我们不应该这样做。

如果不将自定义过滤器移植到 aspnetcore,那么在这里实现什么最合适?
也许我们可以使用基于角色的身份验证 https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles
我们可以创建一个中间件来填充来自授权服务 api 的用户访问权限并将权限展平并将它们作为 ClaimTypes.Role 添加到用户的 ClaimsIdentity 中?然后我们将使用上面的方法,例如:
[Authorize(Roles = "CanSaveContact")]
public ActionResult Save()

这种方法的不合适之处在于,这实际上与角色无关,而更多地与访问权限有关。

我还查看了基于策略的授权:

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies

在 Controller 中可能如下所示:
[Authorize(Policy = "CanSaveContact")]
public ActionResult Save()

但是当我阅读上面基于微软策略的示例中的代码时,我必须将安全服务 api 中存在的所有可用访问权限添加为 ConfigureService 类的 Startup 方法中的策略才能使用它们。我觉得看起来很尴尬(伪代码):
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
IEnumerable<string> allAccessRights = _securtiyService.GetAllAccessRights();

services.AddAuthorization(options =>
{
foreach(var accessRight in allAccessRights)
{
options.AddPolicy(accessRight, policy => policy.Requirements.Add(new AccessRightRequirement(accessRight));

}
});
services.AddSingleton<IAuthorizationHandler, AccessRightHandler>();
}

然后 AccessRightHandler 将负责验证用户的访问权限。编写 AccessRightHandler 是可以的,但似乎没有必要将所有权限添加为策略。

在我们的 aspnetcore 应用程序中实现这种授权的最佳方法是什么?

最佳答案

很好的问题,我认为很多人在升级到 ASP.NET Core 时也会遇到同样的问题。

Barry Dorrans (@blowdart) 是绝对正确的,您不应该编写自己的自定义授权属性 - ASP.NET Core 中的授权已大大改进,您绝对可以根据自己的需要进行调整。

当然,这在很大程度上取决于您当前的应用程序以及您的角色,因此我将根据您上面提供的代码片段做出一些假设。

在开始之前,我真的建议您通读新的 Authorization docs对于 ASP.NET Core,以及 Barry Dorran 的 Authorization workshop在 GitHub 上。我强烈建议您通过后者,他在那里也有一个 .NET Core 2.0 分支。

根据您希望如何实现它,您可以使用基于声明的授权,也可以使用基于资源的授权。

查看您的角色,似乎基于资源的身份验证在您的情况下实际上可以很好地工作!

例如:

确定可能的操作(操作 Name 将从您的资源中获取):

public static class Operations
{
public static OperationAuthorizationRequirement Access = new OperationAuthorizationRequirement { Name = "Access" };
public static OperationAuthorizationRequirement Copy = new OperationAuthorizationRequirement { Name = "Copy" };
public static OperationAuthorizationRequirement Edit = new OperationAuthorizationRequirement { Name = "Edit" };
public static OperationAuthorizationRequirement Save = new OperationAuthorizationRequirement { Name = "Save" };
public static OperationAuthorizationRequirement Delete = new OperationAuthorizationRequirement { Name = "Delete" };
}

创建一个基本资源授权处理程序:
public abstract class BaseResourceAuthorizationHandler<TResource> : AuthorizationHandler<OperationAuthorizationRequirement, TResource>
{
private readonly string _resourceType;
public BaseResourceAuthorizationHandler(string resourceType)
{
_resourceType = resourceType;
}

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement, TResource resource)
{
if (context.User.HasClaim("Resources", $"Can{requirement.Name}{_resourceType}"))
{
context.Succeed(requirement);
}

return Task.CompletedTask;
}
}

实现特定的基于资源的处理程序。资源是将应用程序中的对象绑定(bind)到资源中的实体。此类将成为 ASP.NET Core 中当前资源角色、操作和授权系统之间的粘合剂。这些也可以扩展为任何特定资源类型/操作添加额外的逻辑
例如,对于约会:
public class AppointmentAuthorizationHandler : BaseResourceAuthorizationHandler<Appointment>
{
public AppointmentAuthorizationHandler() : base("Appointment") { }
}

然后您注册:
services.AddSingleton<IAuthorizationHandler, AppointmentAuthorizationHandler>();

然后在您的 Controller 中:
public class AppointmentsController : Controller
{
IAppointmentsRepository _appointmentsRepository;
IAuthorizationService _authorizationService;

public AppointmentsController(IAppointmentsRepository appointmentsRepository,
IAuthorizationService authorizationService)
{
_appointmentsRepository = appointmentsRepository;
_authorizationService = authorizationService;
}

public IActionResult Edit(int id)
{
var appointment = _appointmentsRepository.Get(id);
if (appointment == null)
{
return new NotFoundResult();
}

if (!(await _authorizationService.AuthorizeAsync(User, appointment, Operations.Edit)))
{
return new ChallengeResult();
}

return View(appointment);
}
}

您也可以在 View 中执行相同操作,以检查是否允许用户看到编辑按钮,例如:
@using Microsoft.AspNetCore.Authorization
@model IEnumerable<Appointment>
@inject IAuthorizationService AuthorizationService
<h1>Document Library</h1>
@foreach (var appointment in Model)
{
if (await AuthorizationService.AuthorizeAsync(User, appointment, Operations.Edit))
{
<p>@Html.ActionLink("Appointment #" + appointment.Id, "Edit", new { id = appointment.Id })</p>
}
}

附言只是添加一个注释 - 是的,你失去了按属性过滤的能力,但最终这样更好。首先也是最重要的 - 您远离基于字符串的角色,您根据操作类型和资源类型请求权限。其次,您可以以更好(和更智能的方式)处理权限,以及组合多个权限检查。

它看起来更复杂,但它也更强大:)

关于asp.net-mvc - ASP.NET Core 中基于事件的授权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46318277/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com