Code Monkey home page Code Monkey logo

Comments (10)

daixpham avatar daixpham commented on September 28, 2024

same here !

from authorization.

Shane32 avatar Shane32 commented on September 28, 2024

Can you post a list of the GraphQL-related nuget dependencies you are referencing?

from authorization.

fl99kl avatar fl99kl commented on September 28, 2024

image

from authorization.

Shane32 avatar Shane32 commented on September 28, 2024

Personally, I suggest removing the GraphQL.Server and GraphQL.Authorization packages and using GraphQL.AspNetCore3 instead, which is easy to use and has lots of documentation. We are in the process of replacing all the code in the GraphQL.Server.Transports.AspNetCore package with the code in the GraphQL.AspNetCore3 project, but it may be another month or more until that is complete. GraphQL.AspNetCore3 includes samples for configuration as ASP.Net Core middleware (the easiest way), or as a MVC controller action as it sounds like you have configured now.

You can also use the GraphQL.Server.Transports.AspNetCore and GraphQL.Server.Authorization.AspNetCore packages, but there are a number of authentication features not supported, which are supported in GraphQL.AspNetCore3.

As for your exact situation, can you provide a copy of your GraphQL controller and your DI configuration (as it relates to GraphQL services)? I am guessing that somehow the validation rule is not added to the execution options -- normally this happens automatically, but it can depend on your configuration.

from authorization.

fl99kl avatar fl99kl commented on September 28, 2024

My GraphQL Controller:

using System.Threading.Tasks;
using GraphQL;
using GraphQL.Execution;
using GraphQL.NewtonsoftJson;
using GraphQL.Types;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using rcRegman_CoCreation.Models;
namespace rcRegman_CoCreation.Controllers
{
    [ApiController]
    public class GraphQLController : Controller
    {
        private readonly IDocumentExecuter _executer;
        private readonly ISchema _schema;
        private static readonly GraphQLSerializer _serializer = new();
        public GraphQLController(ISchema schema, IDocumentExecuter executer)
        {
            _schema = schema;
            _executer = executer;
        }
        [Route("graphql")]
        [HttpPost]
        public async Task<cke:object> Post([FromBody] object query)
        {
            GraphqlErrors.Errors.Clear();
            var rawJson = query.ToString();
            var _query = JsonConvert.DeserializeObject<GraphQLQueryDTO>(rawJson);
            var result = await _executer.ExecuteAsync(_ =>
            {
                _.Schema = _schema;
                _.Query = _query.Query;
                _.Variables = _serializer.Deserialize<Inputs>(rawJson); 
                _.UserContext = new GraphQlUserContextDictionary(User);
            });
            if (result.Errors?.Count > 0)
            {
                for (var i = 0; i < result.Errors.Count; i++) GraphqlErrors.Errors.Add(result.Errors[i].Message);
                return BadRequest(GraphqlErrors.Errors);
            }
            var returnObject = new ExecutionResult();
            returnObject.Data =((ExecutionNode)result.Data).ToValue();
            return Ok(returnObject);
        }
    }
}

Statup.cs

public void ConfigureServices(IServiceCollection services)
{       
   ....
             services.AddSingleton<IServiceProvider>(_ => new FuncServiceProvider(_.GetRequiredService));
            // GraphQL Schema
            services.AddSingleton<CompositeQuery>();
            services.AddSingleton<CompositeMutation>();
            // GraphQL Query DI 
            services.AddSingleton<IGraphQueryMarker, CommentQuery>();
   ....
 }

CompositeQuery:

using System.Collections.Generic;
using GraphQL.Types;
using rcRegman_CoCreation.GraphQL.Marker;

namespace rcRegman_CoCreation.GraphQL.Query
{
    public class CompositeQuery : ObjectGraphType
    {
        public CompositeQuery(IEnumerable<IGraphQueryMarker> graphQueryMarkers)
        {
            Name = "CompositeQuery";
            foreach (var marker in graphQueryMarkers)
            {
                var m = marker as ObjectGraphType<object>;
                foreach (var f in m.Fields) AddField(f);
            }
        }
    }
}
public interface IGraphQueryMarker
    {
    }

and CompositeMutation:

using System.Collections.Generic;
using GraphQL.Types;
using rcRegman_CoCreation.GraphQL.Marker;
namespace rcRegman_CoCreation.GraphQL.Mutation
{
    public class CompositeMutation : ObjectGraphType
    {
        public CompositeMutation(IEnumerable<IGraphMutationMarker> graphMutationMarkers)
        {
            Name = "CompositeMutation";
            foreach (var marker in graphMutationMarkers)
            {
                var m = marker as ObjectGraphType;
                foreach (var f in m.Fields) AddField(f);
            }
        }
    }
}

I have also tried changing to the GraphQL.AspNetCore3 package and follow the documentation there. The authorization for all requests works. However I need to protect individual fields and when trying to configure it in startup like:

      services.AddGraphQL(b => b
          .AddSystemTextJson()
          .AddAuthorization()
      );

I'm getting the following error:

System.ArgumentNullException: Value cannot be null. (Parameter 'provider')
   at GraphQL.Utilities.ServiceProviderExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) in /_/src/GraphQL/Utilities/ServiceProviderExtensions.cs:line 22
   at GraphQL.Utilities.ServiceProviderExtensions.GetRequiredService[T](IServiceProvider provider) in /_/src/GraphQL/Utilities/ServiceProviderExtensions.cs:line 11
   at GraphQL.GraphQLBuilderExtensions.<>c__DisplayClass64_0`1.<AddValidationRule>b__0(ExecutionOptions options) in /_/src/GraphQL/GraphQLBuilderExtensions.cs:line 968
   at GraphQL.DI.ConfigureExecutionOptions.<>c__DisplayClass2_0.<.ctor>b__0(ExecutionOptions opt) in /_/src/GraphQL/DI/IConfigureExecutionOptions.cs:line 29
   at GraphQL.DI.ConfigureExecutionOptions.ConfigureAsync(ExecutionOptions executionOptions) in /_/src/GraphQL/DI/IConfigureExecutionOptions.cs:line 34
   at GraphQL.DI.ConfigureExecutionOptionsMapper.<>c__DisplayClass1_0.<<-ctor>b__0>d.MoveNext() in /_/src/GraphQL/DI/IConfigureExecutionOptions.cs:line 55

Maybe this is related to the issue I'm experiencing?

from authorization.

Shane32 avatar Shane32 commented on September 28, 2024

Well the last issue is easy. Set the RequestServices property to the service provider when calling the document executer.

From memory: (I’ll double check in a bit)

_.RequestServices = HttpContext.RequestServices;

from authorization.

Shane32 avatar Shane32 commented on September 28, 2024

You're also missing the cancellation token and the operation name, and variables are deserializing the entire json string rather than just the variables property, and the extensions property is also missing.

            var result = await _executer.ExecuteAsync(_ =>
            {
                _.Schema = _schema;
                _.Query = _query.Query;
                _.OperationName = _query.OperationName;
                _.Variables = _serializer.ReadNode<Inputs>(_query.Variables); // assuming that Variables is of type JsonElement
                _.Extensions = _serializer.ReadNode<Inputs>(_query.Extensions); // assuming that Extensions is of type JsonElement
                _.UserContext = new GraphQlUserContextDictionary(User);
                _.RequestServices = HttpContext.RequestServices;
                _.RequestAborted = HttpContext.RequestAborted;
            });

There's another issue with my sample above, however: you're using Newtonsoft.Json to deserialize rawJson but called AddSystemTextJson to use the System.Text.Json GraphQL deserializer. As such, Variables and Extensions should be a JObject, and in order to read them via ReadNode you need to use AddNewtonsoftJson. Or, use System.Text.Json to deserialize the rawJson.

I would strongly suggest reviewing the controller sample for GraphQL.AspNetCore3:

I also noticed that you registered IServiceProvider. Typically this is provided by your DI implementation and does not need to be registered. If it does need to be registered, it is very important that this is a scoped service, not a singleton. And finally, it's pointing to GetRequiredService instead of GetService, which is incorrect behavior for an IServiceProvider implementation as it will throw an exception if a service is not registered. GraphQL relies on the correct implementation of IServiceProvider.

// remove this line !!!!!
services.AddSingleton<IServiceProvider>(_ => new FuncServiceProvider(_.GetRequiredService));

from authorization.

Shane32 avatar Shane32 commented on September 28, 2024

I updated the controller sample to demonstrate WebSocket support as well, although at that point you might as well use the middleware, which is much simpler to use. Just call app.UseGraphQL("/graphql"); in your startup and you can remove the controller entirely. You'd also probably need to set up the user context builder when you configure GraphQL:

.AddUserContextBuilder(context => new GraphQlUserContextDictionary(context.User));

from authorization.

fl99kl avatar fl99kl commented on September 28, 2024

That did solve the problem. The authorization now works like a charm.

Big thanks to you for your help!

from authorization.

sungam3r avatar sungam3r commented on September 28, 2024

@fl99kl Long story short - add IProvideClaimsPrincipal to your GraphQlUserContextDictionary:

   public class GraphQlUserContextDictionary : Dictionary<string, object>, IProvideClaimsPrincipal
    {
        public ClaimsPrincipal User { get; set; }

        public GraphQlUserContextDictionary(ClaimsPrincipal User)
        {
            this.User = User;
        }
    }

from authorization.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.