使用ASP.NET核心身份的清洁体系结构的授权和身份验证

发布于 2025-01-20 03:18:32 字数 1694 浏览 3 评论 0原文

我是第一次学习干净和垂直切片架构,如果我们使用 ASP.NET Core Identity,我很难理解授权和身份验证的适用范围。而且,在某些情况下,感觉将身份用户(使用用户名、密码、电子邮件等)与任何用户相关的域实体分开会很棘手。

例如,如果我们有一个使用 ASP.NET Core MVC、ASP.NET Core Identity 的解决方案,则示例项目结构可能如下所示:

演示/WebUI 项目:

  • cshtml 视图/Razor 页面与控制器一起住在这里(如果不使用 Razor 页面)。
  • 该项目的program/startup.cs是可以调用其他层的扩展方法的地方:
app.services.InjectInfrastructure(); // same for application

基础设施项目

  • 应用层合约的实现。
  • 数据库上下文。
  • 如果您正在使用存储库,则可能是存储库的实现。

应用程序项目:

  • 命令/查询(假设使用 MassTransit.Mediator 或 MediatR 等)。
  • 验证器(例如使用流畅的验证)。

领域项目:

  • 领域实体(贫血或如果遵循 DDD,则具有方法)。
  • 任何聚合、值对象等(如果使用)。

因此,我们可以有一个具有以下流程的场景:

  1. 调用控制器操作来获取一些数据(表示应用程序层查询),该数据返回渲染的 html(cshtml 视图)。
  2. 数据填充在此 html 页面上,并将 POST 请求(表示应用程序层命令)发送到控制器操作。
  3. 命令或查询是使用 MediatR 发送的。
  4. 命令处理程序运行(使用 dbcontext 或存储库等数据访问),它会验证数据、对数据进行适当的更改并返回响应。
  5. 响应返回到控制器,然后控制器可以确定命令/查询是否成功。
  6. 控制器重定向到另一个操作或填充 ModelState 错误。

我很难区分身份验证问题的情况是,系统中的用户根据他们在登录时所做的选择而具有不同的角色和权限。

例如,在一个教育应用程序中,教师可以选择他们当前代表的学校。在一所学校中,他们可能担任某种角色(例如校长),而在另一所学校中,他们可能担任特权较小的角色。

在这样的场景中,角色、应用程序用户(都是身份问题)似乎与域(将容纳不同的学校和每个学校拥有的角色)紧密耦合。

我的首要问题是,我们如何以干净的架构方式使用 ASP.NET 身份来实现这种身份验证/授权场景?

目前,这种场景带来了多个问题:

  1. 如果我们要解耦身份验证/ 授权场景,来自表示层的授权,我们不能依赖控制器上的 [Authorize(Role = "X")] [Authorize(Policy = "Y")] 装饰器,因为此逻辑应该委托给基础设施 (为了确保如果我们想在任何时候交换表示层,我们不需要重写身份验证/授权)
  2. 这种情况下的用户与域逻辑紧密耦合,因此我只能看到它在与身份相关的实体和域的情况下工作实体被压缩在一个单一的 dbContext

有没有人遇到过/使用干净的架构实现过这样的系统?任何人对此有任何见解都会很棒!

I'm learning about Clean and Vertical Slice Architecture for the first time and I'm having trouble understanding where Authorization and Authentication would fit in if we are using ASP.NET Core Identity. Also it feels as though, in some scenarios, separating the Identity User (with username, password, email etc), from any user related domain entity would be tricky.

For example, if we had a solution which used ASP.NET Core MVC, ASP.NET Core Identity, then an example project structure could be as follows:

Presentation/WebUI Project:

  • cshtml views / Razor pages would live here, along with controllers (if not using Razor pages).
  • The program/startup.cs for this project is where the extension methods from other layers could be called:
app.services.InjectInfrastructure(); // same for application

Infrastructure Project:

  • Implementations of application layer contracts.
  • Database contexts.
  • Perhaps implementations of repositories if you are using them.

Application Project:

  • Commands / queries (assuming using something like MassTransit.Mediator or MediatR).
  • Validators (for example with fluent validation).

Domain Project:

  • Domain entities (anaemic or with methods if following DDD).
  • Any aggregates, value objects etc (if using).

We could therefore have a scenario that has the following flow:

  1. Controller action invoked to get some data (representing the application layer query), which returns rendered html (cshtml view).
  2. Data is populated on this html page and a POST request (representing the application layer Command) is sent to a controller action.
  3. The command or query is sent using MediatR.
  4. Command handler runs (with data access such as dbcontext or repository), which validates, makes the appropriate changes to the data and returns a response.
  5. Response returned to the controller, which can then determine if the command/query has been successful
  6. Controller redirects to another action or populates ModelState errors.

Where I struggle to separate auth concerns is in a scenario where a user in the system has different roles and permissions depending on chocies they make on sign in.

For example, a education application where a teacher can select the school they are currently representing. In one school, they may have a certain role (for example head teacher) and in another they may have a role with lesser privellage.

In a scenario such as this, it seems like the Roles, Application Users (both identity concerns) are tightly coupled with the domain (which would house the different schools and roles that each school has).

My overarching question being, how would we implement this sort of Authentication/Authorization scenario using ASP.NET identity in a clean architecture fashion?

At the moment this scenario poses multiple problems:

  1. If we are to decouple Authentication / Authorization from the presentation layer, we cannot rely on the [Authorize(Role = "X")] [Authorize(Policy = "Y")] decorators on our controllers, as this logic should be delegated to infrastructure
    (to ensure if we wanted to swap presentation layer at any point, we do not need to rewrite authentication / authorization)
  2. The user in this scenario is tightly coupled to the domain logic, so I can only see it working if identity related entities and domain entities are squashed together in a single
    dbContext

Has anyone ever come across / implemented a system like this using clean architecture? Any insight anyone has on this would be great!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一个人的旅程 2025-01-27 03:18:32

因此,您有域层中定义的授权政策?

您只需要将域中定义的“清洁”授权逻辑(策略)连接到ASP.NET核心授权策略,然后继续使用[授权]属性。

authorizationOptions.AddPolicy(YourCleanPolicy.Name, policy =>
{
   policy.AddRequirements(new DomainPolicyRequirement(YourCleanPolicy.Name))
   //or alternatively
   policy.RequireAssertion(ctx => ...)
});

需求Handler可能会访问数据库,并在需要时获取其他用户详细信息,但理想情况下,您iprincipal应该包含所有需要的索赔。您可以通过iClaimStransformation实现这一目标

So you have authorization policies defined in domain layer?

You just need to wire up your "clean" authorization logic (policies) defined in domain to ASP.NET Core Authorization policies and continue using [Authorization] attribute.

authorizationOptions.AddPolicy(YourCleanPolicy.Name, policy =>
{
   policy.AddRequirements(new DomainPolicyRequirement(YourCleanPolicy.Name))
   //or alternatively
   policy.RequireAssertion(ctx => ...)
});

The RequirementHandler might go to the database and fetch additional user details if needed, but ideally you IPrincipal should contain all the claims needed. You can achieve this via IClaimsTransformation

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文