I am attempting to write a Policy-based Authorization Handler. The business logic of the handler needs to use the record id
of the current request that is passed in through the default route.
[Authorize(Roles = "TaskAdmin", Policy = "RecordOwner")]
public IActionResult Index(int id) // <-- Need this id
{
// <snip>
return View();
}
Policy
Here is the class where I need to access the id
route value.
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;
}
}
Startup
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();
}
What I Tried
I tried using the
IHttpContextAccessor
as a constructor parameter ofRecordOwnerHandler
, butIHttpContextAccessor.HttpContext
doesn't seem to contain theRouteData
of the request.I did several Google searches to see if there was any info about how to do this and came up blank.
Then I dug through the source code for both Routing and Model Binding, but can't seem to find an abstraction that is meant for injecting route values into services.
I realize I could try to parse this info out of the URL, but I am hoping for a cleaner way to get the value.
So, how can I access route values and/or value provider data inside of a service in ASP.NET Core 2.0?