I am trying to create a new Authorization requirement, but it must use one of the services that I declare in ConfigureServices, and I have no idea how to pass that service to the new requirement in the same method as declaring the service.
public class NewRequirement: AuthorizationHandler<NewRequirement>, IAuthorizationRequirement
{
private IRepository _repository;
public NewRequirement(IRepository repository)
{
_repository = repository;
}
protected override void Handle(AuthorizationContext context, NewRequirement requirement)
{
//code that uses _repository here
}
}
This works fine, but when I try to add the policy in Startup.cs like this:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSingleton<RepositoryContext>();
services.AddScoped<IRepository, Repository>();
services.Configure<AuthorizationOptions>(options =>
{
options.AddPolicy("NewRequirement", policy => policy.Requirements.Add(new NewRequirement()));
});
}
I get this error
Error CS7036
There is no argument given that corresponds to the required formal parameter 'repository' of 'ExtraProjectRequirements.NewRequirement(IRepository)'
Reception.DNX 4.5.1
I think I need to pass the IRepository to the new policy but I have no idea how to do it in ConfigureServices.
In this article Typically when using policy-based authorization, policies are registered by calling AuthorizationOptions. AddPolicy as part of authorization service configuration.
IAuthorizationRequirement is a marker service with no methods, and the mechanism for tracking whether authorization is successful. Each IAuthorizationHandler is responsible for checking if requirements are met: C# Copy.
Often authorization depends upon the resource being accessed. For example a document may have an author property. Only the document author would be allowed to update it, so the resource must be loaded from the document repository before an authorization evaluation can be made.
Authorizing an action based on the roles assigned to a user. For example, some actions require an administrator role. Resource-based authorization. Authorizing an action based on a particular resource. For example, every resource has an owner.
You are passing the handler to the requirement, which is wrong. IAuthorizationRequirement
and AuthorizationHandler<NewRequirement>
need to be two distinct classes. Also IAuthorizationRequirement
is only a marker interface w/o any mandatory properties or methods, just there to accidentally adding arbitrary classes to the Requirements collection ;)
The IAuthorizationRequirement
will contain pure data (reads: No services, no dependencies that need to be injected) required for your requirement, the handler will validate it. See @blowdart example of an Over18Requirement
and it's handler as well as the official documentation.
Handlers are allowed to have dependencies injected.
Examples from the documentation for future readers (in case link becomes unavailable).
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public MinimumAgeRequirement(int age)
{
MinimumAge = age;
}
protected int MinimumAge { get; set; }
}
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
protected override void Handle(AuthorizationContext context, MinimumAgeRequirement requirement)
{
if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth &&
c.Issuer == "http://contoso.com"))
{
return;
}
var dateOfBirth = Convert.ToDateTime(context.User.FindFirst(
c => c.Type == ClaimTypes.DateOfBirth && c.Issuer == "http://contoso.com").Value);
int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
if (calculatedAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With