Comments (8)
I have given a bit more thought to your problem. I am not sure this is your case, but here are two things that you can do.
1.
Because shield
accepts a JSON object as an argument defining your schema, you could use Object.assign
or ES6
merge syntax to merge your permissions into one.
// Query.allAuthStuffPermissions.ts
export const permissions = {
login: noAuth,
somethingElse: auth
}
// Query.somethingElseEquallyImportant.ts
export const permissions = {
fruits: complexRule,
vegies: simpleRule
}
// index.ts
import { permissions as permissions1 } from 'Query.allAuthStuffPermissions.ts'
import { permissions as permissions2 } from 'Query.somethingElseEquallyImportant.ts'
export default shield({
Query: {
...permissions1,
...permissions2,
}
})
2.
You can logically combine your permissions using logic operators. Available operators are and
, or
and not
. You can read more about them here https://github.com/maticzav/graphql-shield#and-or-not
from graphql-shield.
@leonelpena and others who come across this issue... To accomplish what the OP and myself are looking to do, you can use a library called "assign-deep". https://www.npmjs.com/package/assign-deep.
It merges the permissions together correctly allowing the following:
// file1.js
export default {
Query: {
getSecurityQuestions: allow,
},
SecurityQuestion: {
shortName: allow,
},
};
// file2.js
export default {
Query: {
getUser: allow,
},
};
// permissionsArray is an array of the permissions above like...
// [{Query: {getSecurityQuestions: allow}}, {Query: {getUser: allow}}]
import assign from 'assign-deep';
const permissions = shield(assign(...permissionsArray), {
debug: config.get('graphql.debug'),
fallbackRule: deny,
fallbackError: ApiError('UNAUTHORIZED'),
});
This produces the correct output that graphql-shield needs to operate.
from graphql-shield.
Hey @geminiyellow 👋
I love your suggestion!
Could you give a more concrete example of your case, and maybe explain the issues you are facing now with the current API?
This way we can discuss the API first and later cover a broader problem.
from graphql-shield.
I will close this issue as it seems like it has been solved.
from graphql-shield.
I tried the same approached of merging permissions and I thought the mergeResolvers function provided by https://github.com/okgrow/merge-graphql-schemas could do the work. I read its source code and thought as both structure (permissions vs. resolvers) are almost the same, maybe it could work. So I tried the following:
I have a folder with middlewares
which consist of: index.js
, rules.js
and permissions
folder.
rules.js:
export const isAuthenticated = rule()(async (parent, args, ctx, info) => {
console.log("isAuthenticated...");
return getUserFromCtx(ctx) !== null;
});
export const isAdmin = rule()(async (parent, args, ctx, info) => {
console.log("isAdmin...");
return hasRole(getUserFromCtx(ctx).roles, "ADMIN");
});
Inside permissions folder there are two files: user1.js
and user2.js
. I made this just for experimental purposes.
user1.js:
import { isAdmin } from "../rules";
const user1Permissions = {
Query: {
user: isAdmin,
},
};
export default user1Permissions;
user2.js:
import { and, or, not } from "graphql-shield";
import { isAuthenticated, isAdmin } from "../rules";
const user2Permissions = {
Query: {
allUsers: and(isAuthenticated, isAdmin),
currentUser: isAuthenticated,
},
};
export default user2Permissions;
index.js
import path from 'path';
import {
fileLoader,
mergeResolvers
} from 'merge-graphql-schemas';
import { shield } from "graphql-shield";
const permissions = shield(mergeResolvers(
fileLoader(path.join(__dirname, './permissions'), { extensions: ['.js'] })
));
const middlewares = [
permissions
];
export default middlewares;
My idea is to split the permissions and placed them into the subfolders that are organized by entities which contains the types and resolvers, this way:
+-- entities
| +-- User
| | +-- user.type.gpl
| | +-- user.resolver.js
| | +-- user.permissions.js
I also have logged the follow:
Doing:
console.log(JSON.stringify(fileLoader(path.join(__dirname, './permissions'), { extensions: ['.js'] })));
I get:
[{"Query":{"user":{"name":"0.5497311718774505","cache":"contextual"}}},{"Query":{"allUsers":{"rules":[{"name":"0.12993142526487356","cache":"contextual"},{"name":"0.5497311718774505","cache":"contextual"}]},"currentUser":{"name":"0.12993142526487356","cache":"contextual"}}}]
Doing:
console.log(JSON.stringify(mergeResolvers(
fileLoader(path.join(__dirname, './permissions'), { extensions: ['.js'] })
)));
I get:
{"Query":{"user":{"name":"0.5497311718774505","cache":"contextual"},"allUsers":{"rules":[{"name":"0.12993142526487356","cache":"contextual"},{"name":"0.5497311718774505","cache":"contextual"}]},"currentUser":{"name":"0.12993142526487356","cache":"contextual"}}}
Doing:
const permissions = shield(mergeResolvers(
fileLoader(path.join(__dirname, './permissions'), { extensions: ['.js'] })
));
console.log(permissions);
I get: MiddlewareGenerator { generator: [Function: generator] }
However when I query the endpoint there is no validation for user, both isAdmin and isAuthenticated are not executed. There is no console.log being executed ("isAuthenticated...", "isAdmin...") from rules.js
.
It should be noted that without doing all of these the permissions layer works fine.
So, do you know if this could work? and why it is not working?
from graphql-shield.
@maticzav - This above post is exactly why we need a merge
function. It is all about modularity and re-composability. I want to break apart my permissions entirely and merge them back together in a central location.
from graphql-shield.
Thanks. I have several large massive data sets and it makes no sense to create a thousand line file when each set should have their own permissions and I am connected to each one separately.
I'm using Nexus and graphql-binding depending on the endpoint. It would be able to lock down whole sets of my data with just one check.
for example if I have
fil1.ts
file2.ts
file3.ts
each represents the permissions for a different GraphQL endpoint. I want to be able to merge them all and set one rule that could lock down all of file2.
I feel that when libraries are tested they use the simplest data set possible with only 3 tables. When you have 10 databases or more each with 30 or more tables you don't want to have write rules for every single query/mutation and molecularity is very important. If anything changes, a like a new query added I have to go and change the huge files, when it would make more sense for me to be able to just lock down all mutations on one endpoint with one rule.
from graphql-shield.
FWIW, I use loaddash.merge
, it merges recurisevly and correctly unlike the ... operator which causes the last permission rules to override the others in case of a conflict (e.g. Query)
const permissionRules = merge(
{},
settings.servicePermissionRules ?? {},
builtInPermissionRules
)
from graphql-shield.
Related Issues (20)
- Move from graphql-middleware to Resolvers Composition HOT 4
- 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 HOT 1
- 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
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.