I am trying to implement policy-based authorization in a Hot Chocolate graphql
server.
I am looking at their documentation and also referring to Microsoft's guide
I want that HandleRequirementAsync()
will be called whenever a User query
is being called.
User Policy
in ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddAuthorization(options =>
{
options.AddPolicy("UserPolicy",
policy => policy.Requirements.Add(new UserRequirement()));
});
services.AddSingleton<Query>();
services.AddSingleton<IAuthorizationHandler, UserAuthorizationHandler>();
services.AddSingleton(typeof(IUserRepo), typeof(UserRepo));
services.AddSingleton(typeof(IBookRepository), typeof(BookRepository));
services.AddGraphQL(
SchemaBuilder.New()
.AddAuthorizeDirectiveType()
.AddType<UserType>()
.AddType<BookType>()
.AddQueryType<Query>());
}
User requirement class
and the handler
public class UserAuthorizationHandler : AuthorizationHandler<UserRequirement, IResolverContext>
{
private IHttpContextAccessor _accessor;
public UserAuthorizationHandler([Service] IHttpContextAccessor accessor)
{
_accessor = accessor;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserRequirement requirement,
IResolverContext resource)
{
context.Succeed(requirement);
return Task.CompletedTask;
}
}
public class UserRequirement : IAuthorizationRequirement
{
}
public class UserType
: ObjectType<User>
{
protected override void Configure(IObjectTypeDescriptor<User> descriptor)
{
descriptor.Field(t => t.Name).Type<NonNullType<StringType>>().Authorize("UserPolicy");
descriptor.Field(t => t.Id).Type<NonNullType<StringType>>();
}
}
When running this code. I expect that the HandleRequirementAsync
will be called. This method should always succeed. However, when requesting for user. What actually happens is the the method is not called and the request is immediately denied with this following response:
{
"errors": [
{
"message": "The current user is not authorized to access this resource.",
"locations": [
{
"line": 3,
"column": 5
}
],
"path": [
"user",
"name"
],
"extensions": {
"code": "AUTH_NOT_AUTHENTICATED"
}
}
]
}
I just had an alike problem. In my case I had to ensure that in
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
I had
app.UseAuthentication();
app.UseAuthorization();
first and then
app.UseWebSockets()
.UseGraphQL("/graphql")
.UsePlayground("/graphql")
.UseVoyager("/graphql");