See theAuthorization project for amore in depth implementation of the following idea. Keep in mind that alongside thisproject there is a similarAuthorization.AspNetCoreproject specifically for ASP.NET Core apps.
You can write validation rules that will run before a query is executed. You can use thispattern to check that the user is authenticated or has permissions for a specific field.This example uses theMetadata dictionary available on Fields to set permissions per field.
publicclassMyGraphType:ObjectGraphType{publicMyGraphType(){this.RequirePermission("READ_ONLY");Field(x=> x.Secret).RequirePermission("Admin");}}publicclassRequiresAuthValidationRule:ValidationRuleBase{publicoverrideValueTask<INodeVisitor?>GetPreNodeVisitorAsync(ValidationContext context){var userContext= context.UserContextasGraphQLUserContext;var authenticated= userContext.User?.IsAuthenticated()??false;returnnewValueTask<INodeVisitor?>(newNodeVisitors(newMatchingNodeVisitor<GraphQLOperationDefinition>((op, ctx)=>{if(op.Operation== OperationType.Mutation&&!authenticated){ ctx.ReportError(newValidationError( ctx.Document.Source,"6.1.1",// the rule number of this validation error corresponding to the paragraph number from the official specification$"Authorization is required to access{op.Name}.", op));}}),// this could leak info about hidden fields in error messages// it would be better to implement a filter on the schema so it// acts as if they just don't exist vs. an auth denied error// - filtering the schema is not currently supportednewMatchingNodeVisitor<GraphQLField>((fieldAst, ctx)=>{var fieldDef= ctx.TypeInfo.GetFieldDef();if(fieldDef.RequiresPermissions()&&(!authenticated||!fieldDef.CanAccess(userContext.User.Claims))){ ctx.ReportError(newValidationError( ctx.Document.Source,"6.1.1",// the rule number of this validation error corresponding to the paragraph number from the official specification$"You are not authorized to run this query.", fieldAst));}})));}}publicstaticclassGraphQLExtensions{publicstaticreadonlystring PermissionsKey="Permissions";publicstaticboolRequiresPermissions(thisIProvideMetadata type){var permissions= type.GetMetadata<IEnumerable<string>>(PermissionsKey,newList<string>());return permissions.Any();}publicstaticboolCanAccess(thisIProvideMetadata type,IEnumerable<string> claims){var permissions= type.GetMetadata<IEnumerable<string>>(PermissionsKey,newList<string>());return permissions.All(x=> claims?.Contains(x)??false);}publicstaticboolHasPermission(thisIProvideMetadata type,string permission){var permissions= type.GetMetadata<IEnumerable<string>>(PermissionsKey,newList<string>());return permissions.Any(x=>string.Equals(x, permission));}publicstaticvoidRequirePermission(thisIProvideMetadata type,string permission){var permissions= type.GetMetadata<List<string>>(PermissionsKey);if(permissions==null){ permissions=newList<string>(); type.Metadata[PermissionsKey]= permissions;} permissions.Add(permission);}publicstaticFieldBuilder<TSourceType, TReturnType>RequirePermission<TSourceType, TReturnType>(thisFieldBuilder<TSourceType, TReturnType> builder,string permission){ builder.FieldType.RequirePermission(permission);return builder;}}