Comments (12)
@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.
@maticzav Thank you so much for your patience.
Everything works as expected now 💯
from graphql-shield.
@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.
@maticzav No problem! 🙂
I didn't get your question though. What exactly do you mean by permission system?
from graphql-shield.
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.
@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.
@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.
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.
@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.
@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.
@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.
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)
- Execute root fields rules prior graphql execute phase
- Add the ability to use Fragments and post-execution rules with the single server/schema
- Add Typescript typings to rule args
- Add the ability to attach rules using GraphQL Directives
- CI: add codecov reports
- Provide a way to expose authorization metadata through the graphql schema
- GraphQL Shield Roadmap
- 7.6.4 ESM build broken HOT 5
- Documentation website down HOT 1
- How to use `if` condition in GraphQL Shield HOT 2
- Shield rules type generation based on schema HOT 1
- Feature request: wildcard functionality for field names
- Update [email protected] module to avoid @types/lodash and babel runtime in production deps
- fallbackError loses custom error types
- fallbackRule context information HOT 2
- Question: Is there a way to return objects on rules?
- ..
- Typo in the Docs
- Shield permissions only working properly with 'debug: true' HOT 1
- Performance -- every field wrapped is unnecessarily wrapped in a promise HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from graphql-shield.