使用JWT使用Asp.net核心进行GraphQL身份验证

时间:2018-05-31 16:03:56

标签: authentication asp.net-core graphql graphql-dotnet

我正在使用for GraphQL for .NET包用于graphql。但我无法理解如何在graphql查询或变异中使用JWT进行身份验证。

我读了guide about authorization,但我无法完成。

我需要GraphQL for .NET身份验证的帮助。

任何帮助将不胜感激。

由于

2 个答案:

答案 0 :(得分:1)

该指南围绕授权。您要查找的步骤是身份验证,并且由于可以使用ASP.Net API控制器来实现graphql,因此您可以像使用任何控制器一样实现JWT身份验证。

这是使用Authorize属性的示例grapql控制器。但是,您可以使用过滤器或要完全控制的自定义中间件来实现此功能。

[Route("api/[controller]")]
[ApiController]
[Authorize]
public class GraphQLController : ControllerBase
{
    private readonly IDocumentExecuter executer;
    private readonly ISchema schema;

    public GraphQLController(IDocumentExecuter executer, ISchema schema)
    {
        this.executer = executer;
        this.schema = schema;
    }

    [HttpPost]
    public async Task<ActionResult<object>> PostAsync([FromBody]GraphQLQuery query)
    {
        var inputs = query.Variables.ToInputs();
        var queryToExecute = query.Query;

        var result = await executer.ExecuteAsync(o => {
            o.Schema = schema;
            o.Query = queryToExecute;
            o.OperationName = query.OperationName;
            o.Inputs = inputs;

            o.ComplexityConfiguration = new GraphQL.Validation.Complexity.ComplexityConfiguration { MaxDepth = 15};
            o.FieldMiddleware.Use<InstrumentFieldsMiddleware>();
        }).ConfigureAwait(false);

        return this.Ok(result);
    }
}

public class GraphQLQuery
{
    public string OperationName { get; set; }
    public string Query { get; set; }
    public Newtonsoft.Json.Linq.JObject Variables { get; set; }
}

在Startup.cs中,我配置了JWT承载令牌认证。

希望这会有所帮助。

答案 1 :(得分:0)

我自己也挣扎了两天。我现在正在使用https://github.com/graphql-dotnet/authorization和来自此评论的设置(来自我):https://github.com/graphql-dotnet/authorization/issues/63#issuecomment-553877731

总而言之,您必须为UserContext正确设置AuthorizationValidationRule,如下所示:

public class Startup
{
    public virtual void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddGraphQLAuth(_ =>
        {
            _.AddPolicy("AdminPolicy", p => p.RequireClaim("Role", "Admin"));
        });
        services.AddScoped<IDependencyResolver>(x => new FuncDependencyResolver(x.GetRequiredService));
        services.AddScoped<MySchema>();
        services
            .AddGraphQL(options => { options.ExposeExceptions = true; })
            .AddGraphTypes(ServiceLifetime.Scoped);
        ...
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
    {
        ...
        app.UseMiddleware<MapRolesForGraphQLMiddleware>(); // optional, only when you don't have a "Role" claim in your token
        app.UseGraphQL<MySchema>();
        ...
    }
}

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

        services.AddTransient<IUserContextBuilder>(s => new UserContextBuilder<GraphQLUserContext>(context =>
        {
            var userContext = new GraphQLUserContext
            {
                User = context.User
            };

            return Task.FromResult(userContext);
        }));

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

public class GraphQLUserContext : IProvideClaimsPrincipal
{
    public ClaimsPrincipal User { get; set; }
}

public class MapRolesForGraphQLMiddleware
{
    private readonly RequestDelegate _next;

    public MapRolesForGraphQLMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        // custom mapping code to end up with a "Role" claim
        var metadata = context.User.Claims.SingleOrDefault(x => x.Type.Equals("metadata"));

        if (metadata != null)
        {
            var roleContainer = JsonConvert.DeserializeObject<RoleContainer>(metadata.Value);
            (context.User.Identity as ClaimsIdentity).AddClaim(new Claim("Role", string.Join(", ", roleContainer.Roles)));
        }

        await _next(context);
    }
}

public class RoleContainer
{
    public String[] Roles { get; set; }
}