I am trying to add a handler to my services in Startup.cs. Doing this will give me the following error:
Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Microsoft.AspNetCore.Authorization.IAuthorizationService Lifetime: Transient ImplementationType: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService': Unable to resolve service for type 'Microsoft.AspNetCore.Http.IHttpContextAccessor' while attempting to activate 'ApiPortal.Classes.PolicyAuthorizationHandler')
Here is my Startup.cs
ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
services.Configure<OpenIdConnectOptions>("azure", options =>
{
var existingOnTokenValidatedHandler = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
await existingOnTokenValidatedHandler(context);
await context.HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme, context.Principal);
};
var existingOnUserInformationReceived = options.Events.OnUserInformationReceived;
options.Events.OnUserInformationReceived = async context =>
{
await existingOnUserInformationReceived(context);
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("AzureAccount", policy_builder => policy_builder.AddRequirements(new PolicyRequirement()));
});
services.AddScoped<IAuthorizationHandler, PolicyAuthorizationHandler>();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}
Here is my PolicyAuthorizationHandler.cs
:
public class PolicyAuthorizationHandler : AuthorizationHandler<PolicyRequirement>
{
readonly IHttpContextAccessor _contextAccessor;
public PolicyAuthorizationHandler(IHttpContextAccessor ca)
{
_contextAccessor = ca;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement)
{
if (context.Resource is AuthorizationFilterContext filterContext)
{
var area = "";
var controller = (filterContext.RouteData.Values["controller"] as string)?.ToLower();
var action = (filterContext.RouteData.Values["action"] as string)?.ToLower();
var id = "";
if (await requirement.Pass(context, _contextAccessor, area, controller, action, id))
{
context.Succeed(requirement);
}
}
if (context.Resource is DefaultHttpContext httpContext)
{
var area = "";
var controller = httpContext.Request.RouteValues["controller"].ToString();
var action = httpContext.Request.RouteValues["action"].ToString();
var id = "";
if (await requirement.Pass(context, _contextAccessor, area, controller, action, id))
{
context.Succeed(requirement);
}
}
}
}
Here is my PolicyRequirement.cs
class:
public class PolicyRequirement : IAuthorizationRequirement
{
IHttpContextAccessor _contextAccessor;
AuthorizationHandlerContext _context;
public async Task<bool> Pass(AuthorizationHandlerContext context, IHttpContextAccessor contextAccessor, string area, string controller, string action, string id)
{
_context = context;
_contextAccessor = contextAccessor;
bool authorized = false;
//authorization logic goes here
string email = contextAccessor.HttpContext.User.Identity.Name;
if (email == "[email protected]") authorized = true;
return await Task.FromResult(authorized);
}
}
I have already tried changing services.AddScoped<IAuthorizationHandler, PolicyAuthorizationHandler>()
to services.AddTransient<IAuthorizationHandler, PolicyAuthorizationHandler>()
and services.AddSingleton<IAuthorizationHandler, PolicyAuthorizationHandler>()
. These don't seem to work.
I have also taken a look at this and this thread, but I can't seem to find a solution for my problem here as well.
What am I doing wrong and what can I do to fix this error? Thanks in advance.
CodePudding user response:
This error means that PolicyAuthorizationHandler
class depends on a service of type IHttpContextAccessor
, but that service is not registered in the service container.
you need to register IHttpContextAccessor
in ConfigureServices
by adding line services.AddHttpContextAccessor();
and after this, you can pass IHttpContextAccessor
to the constructor of PolicyAuthorizationHandler
`