Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass UserManager to an AuthorizationHandler in ConfigureServices MVC 6

Given the following class with DI for UserManager

public class AccountAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, AuthorisedAccount>
{
    private readonly UserManager<ApplicationUser> userManager;
    public AccountAuthorizationHandler(UserManager<ApplicationUser> userManager)
    {
        this.userManager = userManager;
    }
    protected override void Handle(AuthorizationContext context,
                                   OperationAuthorizationRequirement requirement,
                                   AuthorisedAccount resource)
    {
        // Pull the user ID claim out from the context.User
        var userId = context.User.GetUserId();
        // Get the current user's account numbers.       
        var user = userManager.Users
            .Include(u => u.AuthorisedAccounts)
            .Where(u => u.Id == userId)
            .FirstOrDefault();

        //Now check if the user's account numbers match the resource accountNumber, and 
        foreach( var authorizedAccount in user.AuthorisedAccounts)
        { 
            if ((resource.AccountNo == authorizedAccount.AccountNo) &&
                (requirement == Operations.Read))
            context.Succeed(requirement);
        }

    }
}

I want to instantiate it in ConfigureServices but it looks like I need to provide Usermanager. ie the responsibility seem to come back to the caller.

services.AddInstance<IAuthorizationHandler>
    (new AccountAuthorizationHandler(I want to add UserManager here));

I guess I thought magically the AuthorizationHandler would resolve the Dependency itself

How to I go about this

Thanks

like image 222
mikes-so Avatar asked Mar 13 '23 20:03

mikes-so


1 Answers

tldr;

You are using the wrong overload.

Try something like this:

services.AddTransient<IAuthorizationHandler, AccountAuthorizationHandler>();

In dependency injection, there is many different concepts and what you used is the equivalent of a singleton.

More details about Dependency Injection

Singleton

There's two way to declare singleton with the ASP.NET dependency injection.

Either you provide the instance yourself with services.AddInstance<T>(...) or you let the system build it for you and control its lifetime so that this single instance will ever be built.

This is done like this:

services.AddSingleton<TInterface, TImplementation>()

Transient lifetime

Everytime a dependency of this type is requested, it will new up the object again. No two instances will be equal since they will always be recreated.

services.AddTransient<TInterface, TImplementation>()

Scoped

At that point, we are requesting for a single object per request. It's a mix of Transient and Singleton but we're only going to new the object once per HTTP request.

services.AddScoped<TInterface, TImplementation>()

Conclusion

Dependency injection is built into the framework from the very beginning. Everything from security to model binding can be overloaded with the right interface and the right lifetime.

You should take a minute and refresh your knowledge on Dependency Injection before going too fast. In case of Not Enough Time, use the provided information in this post. It will be good enough to get you started.

like image 112
Maxime Rouiller Avatar answered Apr 05 '23 16:04

Maxime Rouiller