Search code examples
c#asp.netasp.net-coreaspnetcore-environment

Cannot add Identity to services inside HostBuilder


For context I am coming onto a new project that is using ASPNET Core 7. I am trying to create a custom authorizationHandler for Role management. This part seems to work it fires my custom handler but the user context has no information in it. No claims no nothing. I am impersonating users from the database. After reading the documentation from what I understand the problem is I need to use AddIdentity or AddIdentityCore and add this to services, I found examples of this but never inside this type of inline scaffolding. So adding this inside the configureservices block seems to throw an out of scope error.

System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory1[Microsoft.AspNetCore.Identity.IdentityUser] Lifetime: Scoped ImplementationType: Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory1[Microsoft.AspNetCore.Identity.IdentityUser]': Unable to resolve service for type 'Microsoft.AspNetCore.Identity.IUserStore1[Microsoft.AspNetCore.Identity.IdentityUser]' while attempting to activate 'Microsoft.AspNetCore.Identity.UserManager1[Microsoft.AspNetCore.Identity.IdentityUser]'.) (Error while validating the service descriptor 'ServiceType: Microsoft.AspNetCore.Identity.UserManager1[Microsoft.AspNetCore.Identity.IdentityUser] Lifetime: Scoped ImplementationType: Microsoft.AspNetCore.Identity.UserManager1[Microsoft.AspNetCore.Identity.IdentityUser]': Unable to resolve service for type 'Microsoft.AspNetCore.Identity.IUserStore1[Microsoft.AspNetCore.Identity.IdentityUser]' while attempting to activate 'Microsoft.AspNetCore.Identity.UserManager1[Microsoft.AspNetCore.Identity.IdentityUser]'.)'

Not sure how I can keep the current "WebHostBuilder" scaffolding and include Identity so my Claims are populated.

//program.cs
public static void Main(string[] args)
    {
       CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
       Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseIISIntegration().UseStartup<Startup>();
            })
            .ConfigureServices((hostContext, services) =>
            {
                services.AddSingleton<IAuthorizationHandler, RoleHandler>();
                services.AddAuthorization(options =>
                {
                    options.AddPolicy("Roles", policy =>
                    {
                        policy.Requirements.Add(new RoleAuthRequirement { Role = "Role1" });
                        policy.Requirements.Add(new RoleAuthRequirement { Role = "Role2" });
                        policy.Requirements.Add(new RoleAuthRequirement { Role = "Role3" });

                    });

                });
                services.AddIdentity<IdentityUser, IdentityRole>(); //throws out of scope ERROR!! same as AddIdentityCore
                services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => {
                    options.LoginPath = new PathString("/login");
                    options.AccessDeniedPath = new PathString("/denied");
                });

            });

When logging in I am grabbing the users role from the database and adding it as a Claim

//Login Action                
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
            identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userObj.UserId.ToString()));
            identity.AddClaim(new Claim(ClaimTypes.Name, userObj.UserName));
            identity.AddClaim(new Claim(ClaimTypes.Role, userObj.Role));
            var principal = new ClaimsPrincipal(identity);

await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);

After this in my Authorization handler I cant see any claims the user is null I also cant use User.IsInRole() to verify since the user context is essentially empty.

public class RoleHandler : AuthorizationHandler<RoleAuthRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleAuthRequirement requirement)
    {
        var requiredRole = requirement.Role;

        var hasRole = context.User.IsInRole(requiredRole);

        if (hasRole)
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail(new AuthorizationFailureReason(this, $"User Role {requirement.Role} missing"));
        }
        return Task.CompletedTask;
    }
}

Solution

  • You didn't regist the dbcontext which is required in Identity,Try Regist Identity as below :

    services.AddDbContext<SomeContext>(options =>
    options.UseSqlServer(connectionString));
    services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<SomeContext>();
    

    And After checking your codes,it seems that you are trying Login Attemps with CookieAuthentication(Not Identity) ,Is Identity Really necessary on your side?