GithubHelp home page GithubHelp logo

Comments (12)

maticzav avatar maticzav commented on April 27, 2024 4

@dakshshah96 I have just noticed it. You are not using graphql-yoga. Because of this, you cannot use middlewares property to assign middleware to your schema. To make this work, you have to use graphql-middleware like this;

import { applyMiddleware } from 'graphql-middleware'

const schema = makeExecutableSchema({ typeDefs, resolvers })
const schemaWithPermissions = applyMiddleware(schema, permissions)

Hope this helps you out! 🙂

from graphql-shield.

dakshshah96 avatar dakshshah96 commented on April 27, 2024 1

@maticzav Thank you so much for your patience.

Everything works as expected now 💯

from graphql-shield.

maticzav avatar maticzav commented on April 27, 2024

@dakshshah96 thanks for reporting this! Could you also provide your permission system which caused the error? This would be extremely helpful to reproduce the error and fix it! 🙂

from graphql-shield.

dakshshah96 avatar dakshshah96 commented on April 27, 2024

@maticzav No problem! 🙂

I didn't get your question though. What exactly do you mean by permission system?

from graphql-shield.

maticzav avatar maticzav commented on April 27, 2024

Great! No problem, let me express myself better.

I assume you've written a set of rules and assigned them to specific fields. Could you share the part where you assign rules to your schema using shield function? Rules themselves could be useful too, but are not necessary. 🙂

from graphql-shield.

dakshshah96 avatar dakshshah96 commented on April 27, 2024

@maticzav Got it! Here it is:

const { shield } = require('graphql-shield')
const { permissions } = require('../helpers/auth')
const { makeExecutableSchema } = require('graphql-tools')
const typeDefs = require('./types')
const resolvers = require('./resolvers')

const schema = makeExecutableSchema({ typeDefs, resolvers: shield(resolvers, permissions, { cache: false }) })

module.exports = { schema }

from graphql-shield.

maticzav avatar maticzav commented on April 27, 2024

@dakshshah96 I see! The new version of GraphQL Shield introduced significant API changes - that's why we made a major version bump (2.x.x).

You can find more about implementing the new version in a short article I published https://medium.com/@maticzavadlal/graphql-shield-9d1e02520e35 .

Hope this helps you solve the problem 🙂

from graphql-shield.

dakshshah96 avatar dakshshah96 commented on April 27, 2024

Hey @maticzav, thanks for the clarification! Is this the correct way to implement it? None of my permissions are enforced.

auth.js

const { shield } = require('graphql-shield')
const jwt = require('jsonwebtoken')
const fs = require('fs')
const publicKey = fs.readFileSync(`${__dirname}/rsa/public.pem`)

// role based authorization
const hasRole = (allowedRoles) => (parent, args, context, info) => {
  const Authorization = context.get('authorization')
  if (Authorization) {
    const token = Authorization.replace('Bearer ', '')
    try {
      const decoded = jwt.verify(token, publicKey, { issuer: 'server', algorithms: ['RS256'] })
      context.loggedId = decoded.userId
      context.loggedRole = decoded.role
      return allowedRoles.includes(decoded.role)
    } catch (err) {
      return false
    }
  } else {
    return false
  }
}

/*
    permission definitions (none, admin, user)
*/

const Query = {
  Query: {
    // admin
    allAdmins: hasRole(['admin']),
    // user
    user: hasRole(['user']),
    getUser: hasRole(['admin', 'user']),
    allUsers: hasRole(['admin'])
  }
}

const Mutation = {
  Mutation: {
    // admin
    createAdmin: hasRole(['admin']),
    // user
    createUser: hasRole(['admin']),
    updateUser: hasRole(['admin']),
    verifyUser: hasRole(['admin', 'user']),
    destroyUser: hasRole(['admin'])
  }
}

// merge all permissions
const permissions = shield(Object.assign({}, Query, Mutation), { cache: false })

module.exports = { permissions }

index.js

const { permissions } = require('../helpers/auth')
const { makeExecutableSchema } = require('graphql-tools')
const typeDefs = require('./types')
const resolvers = require('./resolvers')

const schema = makeExecutableSchema({ typeDefs, resolvers, middlewares: [permissions] })

module.exports = { schema }

This is how my /graphql endpoint looks:

app.use('/graphql', bodyParser.json(), graphqlExpress(req => ({ formatError, schema, context: req, validationRules: [NoIntrospection, depthLimit(7)] })))

Sorry for bothering you with this implementation based question 🙂

from graphql-shield.

maticzav avatar maticzav commented on April 27, 2024

@dakshshah96 this looks great! The only problem I noticed is lack of rule assignment. Everything else should work as expected the way you put it; only the cache might be of a problem. I have noticed that you disabled cache, but will post an update and explanation of how to construct rules to make them cachable. 🙂

const hasRole = (allowedRoles) => rule(`has-role-${allowedRoles}`)(async (parent, args, context, info) => {
  const Authorization = context.get('authorization')
  if (Authorization) {
    const token = Authorization.replace('Bearer ', '')
    try {
      const decoded = jwt.verify(token, publicKey, { issuer: 'server', algorithms: ['RS256'] })
      context.loggedId = decoded.userId
      context.loggedRole = decoded.role
      return allowedRoles.includes(decoded.role)
    } catch (err) {
      return false
    }
  } else {
    return false
  }
})

Let me explain what happens here. Since our rules get redefined every time we assign it to a new field (even if the role is the same), Shield hardly guesses what should and what shouldn't be cached together. Because of this, we have to manually define rule name using

rule(`has-role-${allowedRoles}`)

This tells Shield that we know how our data should be bundled. Therefore, we use a specific name to address it.

from graphql-shield.

dakshshah96 avatar dakshshah96 commented on April 27, 2024

@maticzav Thanks, I see!

const { rule, shield } = require('graphql-shield')
const jwt = require('jsonwebtoken')
const fs = require('fs')
const publicKey = fs.readFileSync(`${__dirname}/rsa/public.pem`)

// role based authorization
const hasRole = rule()((allowedRoles) => (parent, args, context, info) => {
  const Authorization = context.get('authorization')
  if (Authorization) {
    const token = Authorization.replace('Bearer ', '')
    try {
      const decoded = jwt.verify(token, publicKey, { issuer: 'server', algorithms: ['RS256'] })
      context.loggedId = decoded.userId
      context.loggedRole = decoded.role
      return allowedRoles.includes(decoded.role)
    } catch (err) {
      return false
    }
  } else {
    return false
  }
})

/*
    permission definitions (none, admin, user)
*/

const Query = {
  Query: {
    // admin
    allAdmins: hasRole(['admin']),
    // user
    user: hasRole(['user']),
    getUser: hasRole(['admin', 'user']),
    allUsers: hasRole(['admin'])
  }
}

const Mutation = {
  Mutation: {
    // admin
    createAdmin: hasRole(['admin']),
    // user
    createUser: hasRole(['admin']),
    updateUser: hasRole(['admin']),
    verifyUser: hasRole(['admin', 'user']),
    destroyUser: hasRole(['admin'])
  }
}

// merge all permissions
const permissions = shield(Object.assign({}, Query, Mutation), { cache: false })

module.exports = { permissions }

How do I use the hasRole function now in the same file? It says that hasRole is not defined.

from graphql-shield.

maticzav avatar maticzav commented on April 27, 2024

@dakshshah96 you have to change

const hasRole = rule()((allowedRoles) => (parent, args, context, info) => {...})

to

const hasRole = (allowedRoles) => rule()((parent, args, context, info) => {...})

from graphql-shield.

dakshshah96 avatar dakshshah96 commented on April 27, 2024

I'm so sorry for the trouble but my permissions are still not enforced 😥 All mutations/queries are allowed.

from graphql-shield.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.