Home > OS >  .NET Core 6: Use my DbContext in Authorization Handler
.NET Core 6: Use my DbContext in Authorization Handler

Time:08-05

I have an authorization handler that needs to pull data from the database to complete the authorization logic. The idea is that users are only allowed to certain areas after posting a given number of blog posts.

Code as follows:

namespace MyProject.Authorisation
{
    public class MinimumPostRequirement : IAuthorizationRequirement
    {
        public MinimumPostRequirement (int postCount)
        {
            PostCount = postCount;
        }

        public int PostCount { get; }
    }

    public class MinimumPostRequirement Handler : AuthorizationHandler<MinimumPostRequirement >
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext authContext, ApprovedUserRequirement requirement)
        {
            
            using (MyDbContext _context = new MyDbContext())
            {
                int? postCount = _context.Posts.Where(post => post.UserName == authContext.User.Identity.Name).Count();

                if(postCount == null)
                {
                    return Task.CompletedTask;
                }

                if(postCount >= requirement.PostCount)
                {
                    authContext.Succeed(requirement);
                }

                return Task.CompletedTask;
            }
           
        }
    }
}

Here is how I declare it in Program.cs:

//DB Connection
var connectionString = builder.Configuration.GetConnectionString("MyConnection");
builder.Services.AddDbContext<MyDbContext>(options => options.UseSqlServer(MyConnection));


//authorisation
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireMinimumPosts", policy => policy.Requirements.Add(new MinimumPostRequirement(3)));
});

builder.Services.AddSingleton<IAuthorizationHandler, MinimumPostRequirementHandler>();

I know there is a dependency injection issue when adding a singleton, so I have also tried using in Program.cs:

builder.Services.AddScoped<IAuthorizationHandler, MinimumPostRequirementHandler>();

And

builder.Services.AddTransient<IAuthorizationHandler, MinimumPostRequirementHandler>();

All result in the following error:

InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.

The database works for all other site operations. The problem only arises when I add [Authorize(Policy = "RequireMinimumPosts")] to the methods I want to restrict.

How would you write this code so that it works? How does dependency injection work in this context? Is there anything I am missing?

CodePudding user response:

Inject the DbContext into the constructor of your MinimumPostRequirementHandler so it will be resolved by the DI container.

public class MinimumPostRequirementHandler
    : AuthorizationHandler<MinimumPostRequirement>
{
    private readonly MyDbContext _dbContext;

    public MinimumPostRequirementHandler( MyDbContext dbContext )
    {
        _dbContext = dbContext;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext authContext, ApprovedUserRequirement requirement)
    {
        // use _dbContext here
    }
}

Register the handler as scoped.

  • Related