Как реализовать авторизацию с использованием GraphQL.NET на уровне функций Resolver?

Я ищу пример кода и примеры того, как реализовать авторизацию на уровне функции распознавателя, используя GraphQL.NET и ASP.NET CORE 2.

В основном я пытаюсь предотвратить выполнение запроса, если запрос не авторизован.

Может кто-нибудь помочь мне получить некоторые хорошие учебники или примеры кода в качестве ссылки для реализации.

1 ответ

Для https://github.com/graphql-dotnet/authorization, страница для AspNetCore не был выпущен, см. Add GraphQL.Server.Authorization.AspNetCore NuGet пакет # 171.

Вы можете реализовать Authorization.AspNetCore для собственного использования.

После реализации Authorization.AspNetCoreВы можете настроить Authorize лайк:

  • 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?}");
            });
        }
    }
    
  • схема

    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");
        }
    }
    

Для полной демонстрации см. GraphQLNet.

Чтобы получить авторизацию GraphQL.Net для работы в ASP.NET Core, сначала установите этот пакет:

GraphQL.Server.Authorization.AspNetCore

В Startup.cs добавьте следующее в ConfigureServices. Не забудьте добавить эти операторы using:

    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
}

Теперь вы сможете использовать AuthorizeWith()на уровне решателя, чтобы защитить поле. Пример:

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

Вы также можете защитить все запросы, добавив this.AuthorizeWith() в верхнюю часть конструктора запроса следующим образом:

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

При этом любой неаутентифицированный доступ к вашей конечной точке GraphQL будет отклонен.

Что касается входа в систему, есть много способов сделать это. Вот быстрый пример аутентификации на основе файлов cookie:

Настройте аутентификацию на основе файлов cookie в Startup.cs' ConfigureServices:

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

Используйте мутацию для входа в систему:

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 };
            });
    }
}
Другие вопросы по тегам