graphql-dotnet / authorization

A toolset for authorizing access to graph types for GraphQL .NET.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

DI in AuthorizationRequirement

Brandon2255p opened this issue · comments

I am struggling to figure out how to inject into an AuthorizationRequirement
I am trying to inject IClient in the following code example.

When setting up the policy, I have to use a constructor which means I am not using DI

                _.AddPolicy(GraphQLPolicyNames.HomeAccess, policy =>
                {
                    policy.AddRequirement(new BasicAccessRequirement());
                    policy.AddRequirement(new HomeAccessRequirement());
                });
    public class HomeAccessRequirement : IAuthorizationRequirement
    {
        private readonly IClient client;
        public HomeAccessRequirement(IClient client)
        {
            this.client = client;
        }
        public Task Authorize(AuthorizationContext context)
        {
            if (AuthorizationHelpers.IsAdminOrSuperAdmin(context.User))
            {
                return Task.FromResult(0);
            }
            var hasId = context.InputVariables.ContainsKey("Id");
            if (hasId)
            {
                dynamic id;
                context.InputVariables.TryGetValue("Id", out id);
                var home = client.GetData(id);
            }

            return Task.FromResult(0);
        }
    }

How can I achieve DI to inject the IClient which is needed for authorization

Unfortunately there is no such possibility.

Instead of making IAuthorizationRequirement DI-dependent, use in as simple class to hold requirement-related information.
And then create a DI-dependent handler (HomeAccessHandler : AuthorizationHandler<HomeAccessRequirement>) to process the requirement.
This should help you.
P.S. Note the "Handler registration" section.

This is core auth package, for ASP.NET Core other one exists.

@sungam3r my bad, missed repo name.

@Brandon2255p how about that?

  services.AddGraphQLAuth((_, s) =>
  {
                _.AddPolicy(GraphQLPolicyNames.HomeAccess, policy =>
                {
                    policy.AddRequirement(s.GetRequiredService<BasicAccessRequirement>());
                    policy.AddRequirement(s.GetRequiredService<HomeAccessRequirement>());
                });
  };

You should of cource configure your requirements in DI-container.

Closed due to lack of feedback.

i tried your solution @sungam3r for a similar issue i'm having but i get System.InvalidOperationException: 'No service for type 'CoreAPI.HomeAccessRequirement' has been registered.'

services.AddSingleton<IAuthorizationRequirement>(x => new HomeAccessRequirement(x.GetRequiredService<IClient>()) );

        `services.AddGraphQLAuth((_, s) =>
        {
            _.AddPolicy("UserRolePolicy", p => p.AddRequirement(s.GetRequiredService<HomeAccessRequirement>()));
        });`

the above did not work, I am relatively new to C# is my error glaringly obvious?

I see how to do it via what @Ekkeir is saying using handlers in Asp.net core but i cannot find an example or how to create a DI handler class for core auth @sungam3r

AddGraphQLAuth is not a part of this project (maybe it is in the server project?), but for using DI it should look closer to this:

services.AddSingleton<HomeAccessRequirement>();


services.AddGraphQLAuth((_, s) =>
{
    _.AddPolicy("UserRolePolicy", p => p.AddRequirement(s.GetRequiredService<HomeAccessRequirement>()));
});

If you register HomeAccessRequirement as IAuthorizationRequirement, then DI does not have a registration of HomeAccessRequirement, only IAuthorizationRequirement.

Also just noticed that you may be referencing #54 (comment) for that extension.

thanks joe, not exactly what i was looking for as i have another service that needs to be injected into HomeAccessRequirement and the above did not work. I am attempting the other route which is to make my injected service available to httpcontextaccessor

If you have another service that needs to be injected, that other service just needs to be also registered with DI. If it doesn't work this way, then it won't work the other way either.

services.AddTransient<HomeAccessRequirement>();
services.AddTransient<IClient, MyClient>();


public class HomeAccessRequirement : IAuthorizationRequirement
{
    private readonly IClient client;
    public HomeAccessRequirement(IClient client)
    {
        this.client = client;
    }
    public Task Authorize(AuthorizationContext context)
    {
        ...
    }
}

services.AddGraphQLAuth((_, s) =>
{
    _.AddPolicy("UserRolePolicy", p => p.AddRequirement(s.GetRequiredService<HomeAccessRequirement>()));
});

thanks! @joemcbride i have been going in circles over and over with this. Seems like I need to look into why I can't dependency inject this...

@mmmikeal Here's a full working example that uses injection in a IAuthorizationRequirement.

graphql-dotnet/examples#66