1+ using System ;
12using System . Collections . Generic ;
23using System . Linq ;
34using System . Threading . Tasks ;
@@ -14,14 +15,25 @@ namespace GraphQL.Authorization
1415 public class AuthorizationValidationRule : IValidationRule
1516 {
1617 private readonly IAuthorizationEvaluator _evaluator ;
18+ private readonly IAuthorizationSkipCondition [ ] _skipConditions ;
1719
1820 /// <summary>
1921 /// Creates an instance of <see cref="AuthorizationValidationRule"/> with
2022 /// the specified authorization evaluator.
2123 /// </summary>
2224 public AuthorizationValidationRule ( IAuthorizationEvaluator evaluator )
25+ : this ( evaluator , null ! )
26+ {
27+ }
28+
29+ /// <summary>
30+ /// Creates an instance of <see cref="AuthorizationValidationRule"/> with
31+ /// the specified authorization evaluator and authorization skip conditions.
32+ /// </summary>
33+ public AuthorizationValidationRule ( IAuthorizationEvaluator evaluator , IEnumerable < IAuthorizationSkipCondition > skipConditions )
2334 {
2435 _evaluator = evaluator ;
36+ _skipConditions = skipConditions ? . ToArray ( ) ?? Array . Empty < IAuthorizationSkipCondition > ( ) ;
2537 }
2638
2739 private bool ShouldBeSkipped ( Operation actualOperation , ValidationContext context )
@@ -77,8 +89,25 @@ void Visit(INode node, int _)
7789 }
7890
7991 /// <inheritdoc />
80- public ValueTask < INodeVisitor ? > ValidateAsync ( ValidationContext context )
92+ public async ValueTask < INodeVisitor ? > ValidateAsync ( ValidationContext context )
8193 {
94+ async ValueTask < bool > ShouldSkipAuthorization ( ValidationContext context )
95+ {
96+ if ( _skipConditions . Length == 0 )
97+ return false ;
98+
99+ foreach ( var skipCondition in _skipConditions )
100+ {
101+ if ( ! await skipCondition . ShouldSkip ( context ) )
102+ return false ;
103+ }
104+
105+ return true ;
106+ }
107+
108+ if ( await ShouldSkipAuthorization ( context ) )
109+ return null ;
110+
82111 var userContext = context . UserContext as IProvideClaimsPrincipal ;
83112 var operationType = OperationType . Query ;
84113 var actualOperation = context . Document . Operations . FirstOrDefault ( x => x . Name == context . OperationName ) ?? context . Document . Operations . FirstOrDefault ( ) ;
@@ -88,14 +117,15 @@ void Visit(INode node, int _)
88117 // acts as if they just don't exist vs. an auth denied error
89118 // - filtering the Schema is not currently supported
90119 // TODO: apply ISchemaFilter - context.Schema.Filter.AllowXXX
91- return new ValueTask < INodeVisitor ? > ( new NodeVisitors (
120+ return new NodeVisitors (
92121 new MatchingNodeVisitor < Operation > ( ( astType , context ) =>
93122 {
94123 if ( context . Document . Operations . Count > 1 && astType . Name != context . OperationName )
95124 {
96125 return ;
97126 }
98127
128+ // Actually, astType always equals actualOperation
99129 operationType = astType . OperationType ;
100130
101131 var type = context . TypeInfo . GetLastType ( ) ;
@@ -148,7 +178,7 @@ void Visit(INode node, int _)
148178 }
149179 }
150180 } )
151- ) ) ;
181+ ) ;
152182 }
153183
154184 private void CheckAuth (
0 commit comments