How to implement authorization using GraphQL.NET at Resolver function level?

不打扰是莪最后的温柔 提交于 2020-02-28 06:41:09

问题


I am looking for sample code and examples regarding how to implement authorization at resolver function level using GraphQL.NET and ASP.NET CORE 2.

Basically I am trying to prevent the execution of query if the request is not authorized.

Can anyone help me to get some good tutorials or code samples as reference for the implementation.


回答1:


For graphql-dotnet/authorization, the page for AspNetCore has not been released, refer Add GraphQL.Server.Authorization.AspNetCore NuGet package #171.

You could implement Authorization.AspNetCore for your own use.

After implement Authorization.AspNetCore, you could configure the Authorize like:

  • Startup.cs

        public class Startup
    {
        public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment)
        {
            Configuration = configuration;
            Environment = hostingEnvironment;
        }
    
        public IConfiguration Configuration { get; }
        public IHostingEnvironment Environment { get; }
    
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
            services.AddAuthentication(option =>
            {
                option.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                option.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                option.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            }).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
            services.AddGraphQL(options =>
            {
                options.EnableMetrics = true;
                options.ExposeExceptions = Environment.IsDevelopment();
    
                //options.
            })
            .AddGraphQLAuthorization(options =>
            {
                options.AddPolicy("Authorized", p => p.RequireAuthenticatedUser());
                //var policy = new AuthorizationPolicyBuilder()
                //                    .
                //options.AddPolicy("Authorized", p => p.RequireClaim(ClaimTypes.Name, "Tom"));
            });
            //.AddUserContextBuilder(context => new GraphQLUserContext { User = context.User });
    
            services.AddSingleton<MessageSchema>();
            services.AddSingleton<MessageQuery>();
    
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }
    
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }
    
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseAuthentication();
            app.UseGraphQL<MessageSchema>("/graphql");
            app.UseGraphQLPlayground(new GraphQLPlaygroundOptions()
            {
                Path = "/ui/playground"
            });
            app.UseGraphiQLServer(new GraphiQLOptions
            {
                GraphiQLPath = "/ui/graphiql",
                GraphQLEndPoint = "/graphql"
            });
    
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
    
  • Schema

    public class MessageQuery : ObjectGraphType<Message>
    {
        public MessageQuery()
        {
            Field(o => o.Content).Resolve(o => "This is Content").AuthorizeWith("Authorized");
            Field(o => o.SentAt);
            Field(o => o.Sub).Resolve(o => "This is Sub");
        }
    }
    

For complete demo, refer GraphQLNet.




回答2:


To get GraphQL.Net's authorization to work in ASP.NET Core, first install this package:

GraphQL.Server.Authorization.AspNetCore

In Startup.cs add the following in ConfigureServices. Make sure to add these using statements:

    using GraphQL.Validation;
    using GraphQL.Server.Authorization.AspNetCore;
public void ConfigureServices(IServiceCollection services)
{
    //... other code

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

    services
        .AddTransient<IValidationRule, AuthorizationValidationRule>()
        .AddAuthorization(options =>
        {
            options.AddPolicy("LoggedIn", p => p.RequireAuthenticatedUser());
        });

    //... other code
}

Now you'll be able to use AuthorizeWith() at the resolver level to protect the field. Example:

public class MyQuery : ObjectGraphType
{
    public MyQuery(ProductRepository productRepository)
    {
        Field<ListGraphType<ProductType>>(
            "products",
            resolve: context => productRepository.GetAllAsync() 
        ).AuthorizeWith("LoggedIn");
    }
}

You can also protect all queries by adding this.AuthorizeWith() to the top of the Query constructor like this:

 public class MyQuery : ObjectGraphType
 {
     public MyQuery(ProductRepository productRepository)
     {
         this.AuthorizeWith("LoggedIn");
         Field<ListGraphType<ProductType>>(
             "products",
             resolve: context => productRepository.GetAllAsync() 
         );
     }
 }

With that, any unauthenticated access to your GraphQL endpoint will be rejected.

Now in terms of logging someone in, there are many ways to do that. Here's a quick Cookie based authentication example:

Configure cookie based authentication in Startup.cs' ConfigureServices:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(o =>
        {
            o.Cookie.Name = "graph-auth";
        });

Use mutation to log someone in:

public class Session
{
    public bool IsLoggedIn { get; set; }
}

public class SessionType : ObjectGraphType<Session>
{
    public SessionType()
    {
        Field(t => t.IsLoggedIn);
    }
}

public class MyMutation : ObjectGraphType
{
    public MyMutation(IHttpContextAccessor contextAccessor)
    {
        FieldAsync<SessionType>(
            "sessions",
            arguments: new QueryArguments(
                new QueryArgument<NonNullGraphType<StringGraphType>> { Name = "password" }),
            resolve: async context =>
            {
                string password = context.GetArgument<string>("password");

                // NEVER DO THIS...for illustration purpose only! Use a proper credential management system instead. :-)
                if (password != "123")
                    return new Session { IsLoggedIn = false };

                var principal = new ClaimsPrincipal(new ClaimsIdentity("Cookie"));
                await contextAccessor.HttpContext.SignInAsync(principal, new AuthenticationProperties
                {
                    ExpiresUtc = DateTime.UtcNow.AddMonths(6),
                    IsPersistent = true
                });

                return new Session { IsLoggedIn = true };
            });
    }
}


来源:https://stackoverflow.com/questions/53537521/how-to-implement-authorization-using-graphql-net-at-resolver-function-level

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!