Skip to content

Commit a5c76de

Browse files
authored
Merge pull request #58 from fossapps/directive
feat(directive): add require permission directive
2 parents b87b486 + ef721d2 commit a5c76de

File tree

6 files changed

+94
-2
lines changed

6 files changed

+94
-2
lines changed

Micro.Auth.Api/GraphQL/AuthSchema.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ public AuthSchema(IServiceProvider services, Query query, Mutation mutation) : b
1111
Query = query;
1212
Mutation = mutation;
1313
Directives.Register(new AuthorizeDirective());
14+
Directives.Register(new RequirePermissionDirective());
1415
RegisterVisitor(typeof(AuthorizeDirectiveVisitor));
16+
RegisterVisitor(typeof(RequirePermissionDirectiveVisitor));
1517
}
1618
}
1719
}

Micro.Auth.Api/GraphQL/Directives/AuthorizeDirective.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public override void VisitObjectFieldDefinition(FieldType field, IObjectGraphTyp
4646

4747
field.Resolver = new AsyncFieldResolver<object>(async context =>
4848
{
49-
throw new NotAuthorizedException();
49+
throw new NotAuthenticatedException();
5050
});
5151
}
5252
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace Micro.Auth.Api.GraphQL.Directives.Exceptions
4+
{
5+
public class NotAuthenticatedException : Exception
6+
{
7+
public NotAuthenticatedException() : base("This operation requires logging in")
8+
{
9+
}
10+
}
11+
}

Micro.Auth.Api/GraphQL/Directives/Exceptions/NotAuthorizedException.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace Micro.Auth.Api.GraphQL.Directives.Exceptions
44
{
55
public class NotAuthorizedException : Exception
66
{
7-
public NotAuthorizedException() : base("This operation requires logging in")
7+
public NotAuthorizedException() : base("You do not have sufficient permission to perform this operation")
88
{
99
}
1010
}

Micro.Auth.Api/GraphQL/Directives/Extensions/Directives.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,32 @@ public static FieldBuilder<TSourceType, TReturnType> Authorize<TSourceType, TRet
1414
{
1515
return type.Directive(AuthorizeDirective.DirectiveName);
1616
}
17+
18+
public static FieldType RequirePermission(this FieldType type, string permission)
19+
{
20+
return type.ApplyDirective(RequirePermissionDirective.DirectiveName, "permission", permission);
21+
}
22+
23+
public static FieldBuilder<TSourceType, TReturnType> RequirePermission<TSourceType, TReturnType>(
24+
this FieldBuilder<TSourceType, TReturnType> type, string permission)
25+
{
26+
return type.Directive(RequirePermissionDirective.DirectiveName, "permission", permission);
27+
}
28+
29+
public static string? GetAppliedPermission(this FieldType fieldType)
30+
{
31+
var applied = fieldType.FindAppliedDirective(RequirePermissionDirective.DirectiveName);
32+
if (applied == null)
33+
{
34+
return null;
35+
}
36+
var arg = applied.FindArgument("permission");
37+
if (arg.Name == "permission")
38+
{
39+
return (string) arg.Value;
40+
}
41+
42+
return null;
43+
}
1744
}
1845
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using GraphQL.Resolvers;
2+
using GraphQL.Types;
3+
using GraphQL.Utilities;
4+
using Micro.Auth.Api.GraphQL.Directives.Exceptions;
5+
using Micro.Auth.Api.GraphQL.Directives.Extensions;
6+
using Microsoft.AspNetCore.Http;
7+
8+
namespace Micro.Auth.Api.GraphQL.Directives
9+
{
10+
public class RequirePermissionDirective : DirectiveGraphType
11+
{
12+
public const string DirectiveName = "requirePermission";
13+
14+
public RequirePermissionDirective() : base(
15+
DirectiveName,
16+
DirectiveLocation.Field,
17+
DirectiveLocation.Mutation,
18+
DirectiveLocation.Query,
19+
DirectiveLocation.FieldDefinition)
20+
{
21+
}
22+
}
23+
public class RequirePermissionDirectiveVisitor : BaseSchemaNodeVisitor
24+
{
25+
private readonly IHttpContextAccessor _contextAccessor;
26+
27+
public RequirePermissionDirectiveVisitor(IHttpContextAccessor contextAccessor)
28+
{
29+
_contextAccessor = contextAccessor;
30+
}
31+
public override void VisitObjectFieldDefinition(FieldType field, IObjectGraphType type, ISchema schema)
32+
{
33+
var permission = field.GetAppliedPermission();
34+
if (permission == null)
35+
{
36+
return;
37+
}
38+
39+
var isAuthorized = _contextAccessor
40+
.HttpContext
41+
?.User
42+
.HasClaim(x => x.Type == "Permission" && x.Value == permission);
43+
44+
if (isAuthorized == true)
45+
{
46+
return;
47+
}
48+
49+
field.Resolver = new AsyncFieldResolver<object>(async context => throw new NotAuthorizedException());
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)