DotNet Core 中 AuthorizationOptions 要求的依赖注入
Dependency Injection on AuthorizationOptions Requirement in DotNet Core
我有一个 .NET 核心项目,我正在尝试使用 AuthorizationOptions 创建自定义策略,如位于此处的文档所示:
ASP.NET.Core Authorization - Dependency Injection in requirement handlers
示例显示了使用 1 个参数设置授权要求 - 一个简单的 int 值。我的自定义要求需要一个字符串参数以及一个 DbContext 对象。我想在运行时将 DbContext 注入到需求的构造函数中。我正在使用 Autofac 容器。我不确定如何实现这一点 - 尝试了几种方法,但到目前为止没有任何效果。
这是我的自定义要求:
public UserNameRequirement(string username, MyDbContext context)
{
_userName = username;
_dbContext = context;
}
在 Startup.cs ConfigureServices 方法中设置授权选项时,文档显示您可以这样注册:
services.AddAuthorization(options =>
{
options.AddPolicy(
"UserNamePolicy",
policy => policy.Requirements.Add(new UserNameRequirement("admin", ** want to resolve and inject my DbContext here **)));
}
我不确定如何实现。我看过这个 post 这是一个类似的问题,但它使用的是 ASP.NET 5 并且该语法不适用于 .net core:
OK,我这里做一个假设,就是你需要在UserNameRequirement
中注入一个MyDbContext
的实例来执行业务逻辑。
如果是这种情况,则意味着 UserNameRequirement
既保存数据(在您的情况下是用户名)又执行授权逻辑。 ASP.NET Core 中的一个例子是 ClaimsAuthorizationRequirement
.
对此的解决方案是将其分成两个 classes - 一方面是只保存与需求关联的数据的需求,另一方面是授权处理程序。请注意,即使我们将通过它,我所描述的内容在 official ASP.NET Core docs.
中可用
所以要求 class 可能类似于:
public class UserNameRequirement : IAuthorizationRequirement
{
public UserNameRequirement(string userName)
{
UserName = userName;
}
public string UserName { get; }
}
处理程序 class 将是:
public class UserNameRequirementHandler : AuthorizationHandler<UserNameRequirement>
{
private readonly MyDbContext _dbContext;
public UserNameRequirementHandler(MyDbContext dbContext)
{
_dbContext = dbContext;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserNameRequirement requirement)
{
var userName = requirement.UserName;
// Use _dbContext to perform business logic
}
}
接下来也是最后一部分是在容器中注册处理程序:
services.AddSingleton<IAuthorizationHandler, UserNameRequirementHandler>();
这样做的效果是,您现在可以将您的要求添加到政策中,而不必担心 DbContext
:
services.AddAuthorization(options =>
{
options.AddPolicy(
"UserNamePolicy",
policy => policy.Requirements.Add(new UserNameRequirement("admin")));
}
在内部,ASP.NET然后会通过容器解析与该需求关联的所有处理程序,因此MyDbContext
的实例将在处理程序中可供您使用,让您执行业务你认为合适的逻辑。
希望我的假设是正确的,这对你有帮助。
编辑:
Henry Roux 在下面的评论中提出了一个很好的观点,即如果 UserNameRequirementHandler
被注册为单例,那么将使用 MyDbContext
的单个实例,这可能会导致问题。确保使用适当的生命周期注册授权处理程序。
您也可以使用 GetRequiredService 方法:
public class ExampleRequirement : AuthorizationHandler<ExampleRequirement>, IAuthorizationRequirement
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ExampleRequirement requirement)
{
UserManager<ApplicationUser> UserManager = ((ActionContext)context.Resource).HttpContext.RequestServices.GetRequiredService<UserManager<ApplicationUser>>();
// you can work with the users ...
return Task.CompletedTask;
}
}
我有一个 .NET 核心项目,我正在尝试使用 AuthorizationOptions 创建自定义策略,如位于此处的文档所示:
ASP.NET.Core Authorization - Dependency Injection in requirement handlers
示例显示了使用 1 个参数设置授权要求 - 一个简单的 int 值。我的自定义要求需要一个字符串参数以及一个 DbContext 对象。我想在运行时将 DbContext 注入到需求的构造函数中。我正在使用 Autofac 容器。我不确定如何实现这一点 - 尝试了几种方法,但到目前为止没有任何效果。
这是我的自定义要求:
public UserNameRequirement(string username, MyDbContext context)
{
_userName = username;
_dbContext = context;
}
在 Startup.cs ConfigureServices 方法中设置授权选项时,文档显示您可以这样注册:
services.AddAuthorization(options =>
{
options.AddPolicy(
"UserNamePolicy",
policy => policy.Requirements.Add(new UserNameRequirement("admin", ** want to resolve and inject my DbContext here **)));
}
我不确定如何实现。我看过这个 post 这是一个类似的问题,但它使用的是 ASP.NET 5 并且该语法不适用于 .net core:
OK,我这里做一个假设,就是你需要在UserNameRequirement
中注入一个MyDbContext
的实例来执行业务逻辑。
如果是这种情况,则意味着 UserNameRequirement
既保存数据(在您的情况下是用户名)又执行授权逻辑。 ASP.NET Core 中的一个例子是 ClaimsAuthorizationRequirement
.
对此的解决方案是将其分成两个 classes - 一方面是只保存与需求关联的数据的需求,另一方面是授权处理程序。请注意,即使我们将通过它,我所描述的内容在 official ASP.NET Core docs.
中可用所以要求 class 可能类似于:
public class UserNameRequirement : IAuthorizationRequirement
{
public UserNameRequirement(string userName)
{
UserName = userName;
}
public string UserName { get; }
}
处理程序 class 将是:
public class UserNameRequirementHandler : AuthorizationHandler<UserNameRequirement>
{
private readonly MyDbContext _dbContext;
public UserNameRequirementHandler(MyDbContext dbContext)
{
_dbContext = dbContext;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserNameRequirement requirement)
{
var userName = requirement.UserName;
// Use _dbContext to perform business logic
}
}
接下来也是最后一部分是在容器中注册处理程序:
services.AddSingleton<IAuthorizationHandler, UserNameRequirementHandler>();
这样做的效果是,您现在可以将您的要求添加到政策中,而不必担心 DbContext
:
services.AddAuthorization(options =>
{
options.AddPolicy(
"UserNamePolicy",
policy => policy.Requirements.Add(new UserNameRequirement("admin")));
}
在内部,ASP.NET然后会通过容器解析与该需求关联的所有处理程序,因此MyDbContext
的实例将在处理程序中可供您使用,让您执行业务你认为合适的逻辑。
希望我的假设是正确的,这对你有帮助。
编辑:
Henry Roux 在下面的评论中提出了一个很好的观点,即如果 UserNameRequirementHandler
被注册为单例,那么将使用 MyDbContext
的单个实例,这可能会导致问题。确保使用适当的生命周期注册授权处理程序。
您也可以使用 GetRequiredService 方法:
public class ExampleRequirement : AuthorizationHandler<ExampleRequirement>, IAuthorizationRequirement
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ExampleRequirement requirement)
{
UserManager<ApplicationUser> UserManager = ((ActionContext)context.Resource).HttpContext.RequestServices.GetRequiredService<UserManager<ApplicationUser>>();
// you can work with the users ...
return Task.CompletedTask;
}
}