You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

56 lines
1.8 KiB

  1. const { SchemaDirectiveVisitor } = require('graphql-tools')
  2. const { defaultFieldResolver } = require('graphql')
  3. const _ = require('lodash')
  4. class AuthDirective extends SchemaDirectiveVisitor {
  5. visitObject(type) {
  6. this.ensureFieldsWrapped(type)
  7. type._requiredAuthScopes = this.args.requires
  8. }
  9. // Visitor methods for nested types like fields and arguments
  10. // also receive a details object that provides information about
  11. // the parent and grandparent types.
  12. visitFieldDefinition(field, details) {
  13. this.ensureFieldsWrapped(details.objectType)
  14. field._requiredAuthScopes = this.args.requires
  15. }
  16. visitArgumentDefinition(argument, details) {
  17. this.ensureFieldsWrapped(details.objectType)
  18. argument._requiredAuthScopes = this.args.requires
  19. }
  20. ensureFieldsWrapped(objectType) {
  21. // Mark the GraphQLObjectType object to avoid re-wrapping:
  22. if (objectType._authFieldsWrapped) return
  23. objectType._authFieldsWrapped = true
  24. const fields = objectType.getFields()
  25. Object.keys(fields).forEach(fieldName => {
  26. const field = fields[fieldName]
  27. const { resolve = defaultFieldResolver } = field
  28. field.resolve = async function (...args) {
  29. // Get the required scopes from the field first, falling back
  30. // to the objectType if no scopes is required by the field:
  31. const requiredScopes = field._requiredAuthScopes || objectType._requiredAuthScopes
  32. if (!requiredScopes) {
  33. return resolve.apply(this, args)
  34. }
  35. const context = args[2]
  36. if (!context.req.user) {
  37. throw new Error('Unauthorized')
  38. }
  39. if (!_.some(context.req.user.permissions, pm => _.includes(requiredScopes, pm))) {
  40. throw new Error('Forbidden')
  41. }
  42. return resolve.apply(this, args)
  43. }
  44. })
  45. }
  46. }
  47. module.exports = AuthDirective