Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using dependency injection in AuthorizationRequirement #54

Closed
joacoleza opened this issue Jun 4, 2019 · 9 comments
Closed

Using dependency injection in AuthorizationRequirement #54

joacoleza opened this issue Jun 4, 2019 · 9 comments
Labels
question Further information is requested

Comments

@joacoleza
Copy link

Hi, as I need one registered service to evaluate the authorization, is there a way to use Dependency Injection when implementing IAuthorizationRequirement ?

I want to achieve something similar to handlers in in ASP.NET Core.

Thanks!

@joacoleza
Copy link
Author

joacoleza commented Jun 5, 2019

I ended adding to my GraphQLUserContext (which implements IProvideClaimsPrincipal) a HttpContext property. This property is being set when constructing it on the GraphQLUserContextBuilder (as HttpContext is a parameter of the method BuildUserContext).

Then, when implementing my IAuthorizationRequirement on the Authorize method I can access the registered service from the HttpContext doing:

HttpContext httpContext = ((GraphQLUserContext)context.UserContext).HttpContext;
var myService = (IMyService)httpContext.RequestServices.GetService(typeof(IMyService));

Is there a better way of doing so?

@joemcbride
Copy link
Member

joemcbride commented Jun 5, 2019

Here's an alternative way to do it:

public class MyReq : IAuthorizationRequirement
{
    private readonly IHttpContextAccessor accessor;

    public MyReq(IHttpContextAccessor accessor)
    {
        this.accessor = accessor;
    }

    public Task Authorize(AuthorizationContext context)
    {
        return Task.CompletedTask;
    }
}

public static class GraphQLAuthExtensions
{
    public static void AddGraphQLAuth(this IServiceCollection services, Action<AuthorizationSettings, IServiceProvider> configure)
    {
        services.AddHttpContextAccessor();
        services.AddTransient<IAuthorizationEvaluator, AuthorizationEvaluator>();
        services.AddTransient<IValidationRule, AuthorizationValidationRule>();
        services.AddTransient<MyReq>();

        services.TryAddTransient(s =>
        {
            var authSettings = new AuthorizationSettings();
            configure(authSettings, s);
            return authSettings;
        });
    }
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddGraphQLAuth((_, s) =>
    {
        _.AddPolicy("SomePolicy", p => p.AddRequirement(s.GetService<MyReq>()));
    });
}

@sungam3r
Copy link
Member

sungam3r commented Jun 5, 2019

Instead of

   services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

you can use special method

  services.AddHttpContextAccessor();

from Microsoft.AspNetCore.Http what does exacly the same thing.

@joemcbride
Copy link
Member

I updated IAuthorizationEvaluator in the example to be registered as Transient. Otherwise AuthorizationSettings would become a singleton indirectly.

@sungam3r
Copy link
Member

sungam3r commented Jun 5, 2019

Enabling scope validation on DI-container may help to find such problems.

@joacoleza
Copy link
Author

Here's an alternative way to do it:

public class MyReq : IAuthorizationRequirement
{
    private readonly IHttpContextAccessor accessor;

    public MyReq(IHttpContextAccessor accessor)
    {
        this.accessor = accessor;
    }

    public Task Authorize(AuthorizationContext context)
    {
        return Task.CompletedTask;
    }
}

public static class GraphQLAuthExtensions
{
    public static void AddGraphQLAuth(this IServiceCollection services, Action<AuthorizationSettings, IServiceProvider> configure)
    {
        services.AddHttpContextAccessor();
        services.AddTransient<IAuthorizationEvaluator, AuthorizationEvaluator>();
        services.AddTransient<IValidationRule, AuthorizationValidationRule>();
        services.AddTransient<MyReq>();

        services.TryAddTransient(s =>
        {
            var authSettings = new AuthorizationSettings();
            configure(authSettings, s);
            return authSettings;
        });
    }
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddGraphQLAuth((_, s) =>
    {
        _.AddPolicy("SomePolicy", p => p.AddRequirement(s.GetService<MyReq>()));
    });
}

Thanks! I'll do it this way

@mmmikeal
Copy link

this is incredibly helpful @joacoleza , do you have an example of how you added the service you want injected to the httpcontext and how you retrieve it out of the httpcontext? i am getting some type errors

@mmmikeal
Copy link

for example in my AddGraphQLAuth i have

services.AddHttpContextAccessor(); services.AddTransient<MyServiceToBeInjected>();

and in my requirement i attempt to access it by
var service = accessor.HttpContext.RequestServices.GetService<MyServiceToBeInjected>();

@joacoleza
Copy link
Author

this is incredibly helpful @joacoleza , do you have an example of how you added the service you want injected to the httpcontext and how you retrieve it out of the httpcontext? i am getting some type errors

I no longer have access to the code where this was implemented. Sorry I couldn’t be more help.

@sungam3r sungam3r added the question Further information is requested label Dec 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants