Skip to content

Commit

Permalink
Merge pull request #58 from fossapps/directive
Browse files Browse the repository at this point in the history
feat(directive): add require permission directive
  • Loading branch information
cyberhck committed Jun 26, 2021
2 parents b87b486 + ef721d2 commit a5c76de
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 2 deletions.
2 changes: 2 additions & 0 deletions Micro.Auth.Api/GraphQL/AuthSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ public AuthSchema(IServiceProvider services, Query query, Mutation mutation) : b
Query = query;
Mutation = mutation;
Directives.Register(new AuthorizeDirective());
Directives.Register(new RequirePermissionDirective());
RegisterVisitor(typeof(AuthorizeDirectiveVisitor));
RegisterVisitor(typeof(RequirePermissionDirectiveVisitor));
}
}
}
2 changes: 1 addition & 1 deletion Micro.Auth.Api/GraphQL/Directives/AuthorizeDirective.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public override void VisitObjectFieldDefinition(FieldType field, IObjectGraphTyp

field.Resolver = new AsyncFieldResolver<object>(async context =>
{
throw new NotAuthorizedException();
throw new NotAuthenticatedException();
});
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace Micro.Auth.Api.GraphQL.Directives.Exceptions
{
public class NotAuthenticatedException : Exception
{
public NotAuthenticatedException() : base("This operation requires logging in")
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Micro.Auth.Api.GraphQL.Directives.Exceptions
{
public class NotAuthorizedException : Exception
{
public NotAuthorizedException() : base("This operation requires logging in")
public NotAuthorizedException() : base("You do not have sufficient permission to perform this operation")
{
}
}
Expand Down
27 changes: 27 additions & 0 deletions Micro.Auth.Api/GraphQL/Directives/Extensions/Directives.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,32 @@ public static FieldBuilder<TSourceType, TReturnType> Authorize<TSourceType, TRet
{
return type.Directive(AuthorizeDirective.DirectiveName);
}

public static FieldType RequirePermission(this FieldType type, string permission)
{
return type.ApplyDirective(RequirePermissionDirective.DirectiveName, "permission", permission);
}

public static FieldBuilder<TSourceType, TReturnType> RequirePermission<TSourceType, TReturnType>(
this FieldBuilder<TSourceType, TReturnType> type, string permission)
{
return type.Directive(RequirePermissionDirective.DirectiveName, "permission", permission);
}

public static string? GetAppliedPermission(this FieldType fieldType)
{
var applied = fieldType.FindAppliedDirective(RequirePermissionDirective.DirectiveName);
if (applied == null)
{
return null;
}
var arg = applied.FindArgument("permission");
if (arg.Name == "permission")
{
return (string) arg.Value;
}

return null;
}
}
}
52 changes: 52 additions & 0 deletions Micro.Auth.Api/GraphQL/Directives/RequirePermissionDirective.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using GraphQL.Resolvers;
using GraphQL.Types;
using GraphQL.Utilities;
using Micro.Auth.Api.GraphQL.Directives.Exceptions;
using Micro.Auth.Api.GraphQL.Directives.Extensions;
using Microsoft.AspNetCore.Http;

namespace Micro.Auth.Api.GraphQL.Directives
{
public class RequirePermissionDirective : DirectiveGraphType
{
public const string DirectiveName = "requirePermission";

public RequirePermissionDirective() : base(
DirectiveName,
DirectiveLocation.Field,
DirectiveLocation.Mutation,
DirectiveLocation.Query,
DirectiveLocation.FieldDefinition)
{
}
}
public class RequirePermissionDirectiveVisitor : BaseSchemaNodeVisitor
{
private readonly IHttpContextAccessor _contextAccessor;

public RequirePermissionDirectiveVisitor(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
public override void VisitObjectFieldDefinition(FieldType field, IObjectGraphType type, ISchema schema)
{
var permission = field.GetAppliedPermission();
if (permission == null)
{
return;
}

var isAuthorized = _contextAccessor
.HttpContext
?.User
.HasClaim(x => x.Type == "Permission" && x.Value == permission);

if (isAuthorized == true)
{
return;
}

field.Resolver = new AsyncFieldResolver<object>(async context => throw new NotAuthorizedException());
}
}
}

0 comments on commit a5c76de

Please sign in to comment.