1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 |
- const { SchemaDirectiveVisitor } = require('graphql-tools')
- const { defaultFieldResolver } = require('graphql')
- const _ = require('lodash')
- class AuthDirective extends SchemaDirectiveVisitor {
- visitObject(type) {
- this.ensureFieldsWrapped(type)
- type._requiredAuthScopes = this.args.requires
- }
- // Visitor methods for nested types like fields and arguments
- // also receive a details object that provides information about
- // the parent and grandparent types.
- visitFieldDefinition(field, details) {
- this.ensureFieldsWrapped(details.objectType)
- field._requiredAuthScopes = this.args.requires
- }
- visitArgumentDefinition(argument, details) {
- this.ensureFieldsWrapped(details.objectType)
- argument._requiredAuthScopes = this.args.requires
- }
- ensureFieldsWrapped(objectType) {
- // Mark the GraphQLObjectType object to avoid re-wrapping:
- if (objectType._authFieldsWrapped) return
- objectType._authFieldsWrapped = true
- const fields = objectType.getFields()
- Object.keys(fields).forEach(fieldName => {
- const field = fields[fieldName]
- const { resolve = defaultFieldResolver } = field
- field.resolve = async function (...args) {
- // Get the required scopes from the field first, falling back
- // to the objectType if no scopes is required by the field:
- const requiredScopes = field._requiredAuthScopes || objectType._requiredAuthScopes
- if (!requiredScopes) {
- return resolve.apply(this, args)
- }
- const context = args[2]
- if (!context.req.user) {
- throw new Error('Unauthorized')
- }
- if (!_.some(context.req.user.permissions, pm => _.includes(requiredScopes, pm))) {
- throw new Error('Forbidden')
- }
- return resolve.apply(this, args)
- }
- })
- }
- }
- module.exports = AuthDirective
|