是否有比使用IAsyncActionFilter来授权用户充当特定记录或用户ID在数据库中的特定记录更好的方法 [英] Is there a better way than using an IAsyncActionFilter to authorize if user is in role or user id is in database for specific record
问题描述
要求: 有一些控制器方法只能在以下情况下调用:
Requirement: There are some controller methods which only can be called if:
1.用户的角色为"TaskAdmin"
OR
2.用户负责将在控制器方法中修改的数据库对象(只有一列需要比较的用户ID).此数据表中的记录可以更改,并且不能硬编码".
我知道解决此问题的两种可能性:
-
创建2个方法.一种具有属性
[Authorize(Roles = "TaskAdmin")]
,另一种将在属性中检查用户是否对数据库对象负责.
Create 2 methods. One with the attribute
[Authorize(Roles = "TaskAdmin")]
and one where it will be checked if the user is responsible for the database object.
创建一个IAsyncActionFilter
来同时检查需求和TypeFilterAttribute
以便在控制器方法上使用.
Create an IAsyncActionFilter
which checks both requirements and a TypeFilterAttribute
to use on the controller methods.
(使用ASP.NET Core)有更好的方法吗?
推荐答案
是否有更好的方法(使用ASP.NET Core)?
Is there a better way to do this (with ASP.NET Core)?
是的.您可以使用基于策略的授权来实现复杂的权限基于规则.
Yes. You can use Policy Based Authorization to implement complex permission-based rules.
public class RecordOwnerRequirement : IAuthorizationRequirement
{
}
public class RecordOwnerHandler : AuthorizationHandler<RecordOwnerRequirement>
{
private readonly ApplicationDbContext dbContext;
private readonly IActionContextAccessor actionContextAccessor;
public RecordOwnerHandler(ApplicationDbContext dbContext, IActionContextAccessor actionContextAccessor)
{
this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
this.actionContextAccessor = actionContextAccessor ?? throw new ArgumentNullException(nameof(actionContextAccessor));
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RecordOwnerRequirement requirement)
{
if (IsUserAuthorized(context))
{
context.Succeed(requirement);
}
//TODO: Use the following if targeting a version of
//.NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
private bool IsUserAuthorized(AuthorizationHandlerContext context)
{
var id = this.actionContextAccessor.ActionContext.RouteData.Values["id"];
// Use the dbContext to compare the id against the database...
// Return the result
return true;
}
}
Startup.cs
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
//*********************************************************************
// Add policy for record owner
services.AddAuthorization(options =>
{
options.AddPolicy("RecordOwner", policy =>
policy.Requirements.Add(new RecordOwnerRequirement()));
});
//*********************************************************************
// Add application services.
services.AddTransient<IEmailSender, EmailSender>();
//*********************************************************************
// Register record owner handler with the DI container
services.AddTransient<IAuthorizationHandler, RecordOwnerHandler>();
services.AddTransient<IActionContextAccessor, ActionContextAccessor>();
//*********************************************************************
services.AddMvc();
}
用法
public class HomeController : Controller
{
[Authorize(Roles = "TaskAdmin", Policy = "RecordOwner")]
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
}
这篇关于是否有比使用IAsyncActionFilter来授权用户充当特定记录或用户ID在数据库中的特定记录更好的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!