如何在ASP.NET Core 2.0中访问服务中的Route Data/Value Provider数据?

Nig*_*888 5 c# asp.net-mvc dependency-injection asp.net-core asp.net-core-2.0

我正在尝试编写基于策略的授权处理程序.处理程序的业务逻辑需要使用id通过默认路由传递的当前请求的记录.

[Authorize(Roles = "TaskAdmin", Policy = "RecordOwner")]
public IActionResult Index(int id) // <-- Need this id
{
    // <snip>

    return View();
}
Run Code Online (Sandbox Code Playgroud)

政策

这是我需要访问id路由值的类.

public class RecordOwnerHandler : AuthorizationHandler<RecordOwnerRequirement>
{
    private readonly ApplicationDbContext dbContext;

    public RecordOwnerHandler(ApplicationDbContext dbContext)
    {
        this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
    }

    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)
    {
        //****************************************
        // Need the id here...
        //****************************************

        // Return the result
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

启动

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.AddMvc();
}
Run Code Online (Sandbox Code Playgroud)

我试过的

  1. 我尝试使用IHttpContextAccessoras作为构造函数参数RecordOwnerHandler,但IHttpContextAccessor.HttpContext似乎不包含RouteData请求.

  2. 我做了几次谷歌搜索,看看是否有任何关于如何做到这一点的信息,并且空白.

  3. 然后我挖掘了路由模型绑定的源代码,但似乎找不到用于将路由值注入服务的抽象.

我意识到我可以尝试从URL中解析这些信息,但我希望有一种更清晰的方法来获取价值.

那么,如何在ASP.NET Core 2.0中访问服务内部的路由值和/或值提供者数据?

Nig*_*888 9

可以使用ActionContextAccessor该类访问路径值.

DI注册

services.AddTransient<IActionContextAccessor, ActionContextAccessor>();
Run Code Online (Sandbox Code Playgroud)

用法

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)
    {
        // Now the id route value can be accessed directly...
        var id = this.actionContextAccessor.ActionContext.RouteData.Values["id"];

        // Use the dbContext to compare the id against the database...

        // Return the result
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:我仍然想找到一种方法来访问值提供程序来执行此操作,因此如果通过路由值,查询字符串,表单值等传递参数也无关紧要.


小智 7

为了供将来参考,从 .NET Core 5.0 开始,现在改为传递 HttpContext,因此您可以执行以下操作:

if (context.Resource is HttpContext httpContext)
{
   var value = httpContext.GetRouteValue("key");
}
Run Code Online (Sandbox Code Playgroud)

请参阅此参考[AspNetCore] 端点路由中的授权资源现在将是 HttpContext