Allow specifying rules for both types and fields
luhagel opened this issue Β· comments
Feature request
Is your feature request related to a problem? Please describe
As far as I'm aware, right now you can specify shield rules for either a type or a selection of subfields on that type, but not both.
So if I wanted to restrict access to users that have been archieved, I can do that no problem, if I want to restrict access so only the current user can see their respective address, no problem either, but I'm not aware of a way to combine the two.
Describe the solution you'd like
Implementing this might be really hard to implement without breaking anything. Ideally you'd have the option to introduce an special field into your type permissions that handles the type permissions, as that would hopefully be the least invasive.
So somethina long the lines of:
shield({
User: {
_canViewModel: rules.notArchieved,
address: rules.isCurrentUser
})
Describe alternatives you've considered
Other solutions would include changing the internal shieldRules schema to diffrentiate between subfields and the parent type, or having a diffrent naming convention for the two, along the lines of User: {...}, Usertype: rule
, but both of those wouldd probably break to much existing code.
Additional context
Hey @luhagel π,
Thank you for opening an issue. We will get back to you as soon as we can. Also, check out our Open Collective and consider contributing financially.
https://opencollective.com/graphql-shield
PS.: We offer
priority
support for all financial contributors. Don't forget to addpriority
label once you start contributing π
Hey @luhagel π ,
Thank you for opening the issue. I had a similar idea a long time ago that would allow us to use and
, or
, and other logical patterns on dictionaries as well as rules. In the case of dictionaries, we would simply merge the rules at the lower level.
For example,
const permissions = shield({
Query: and(isAuthenticated, {
fruits: or(isAdmin, isEditor),
customers: isAdmin,
},
})
would translate to
const permissions = shield({
Query: {
fruits: and(isAuthenticated, or(isAdmin, isEditor)),
customers: and(isAuthenticated, isAdmin),
}
})
Is that what you had in mind?
It's one of the last things that I think are truly missing from the library alongside race
rule (#645).
I am sad to say this, but since this library lost its funding, I am not sure when I'll find time to implement these features.
Exactly!
I might be able to look into this as well, given I find some time off.
Just wanted to make sure this wasn't already a thing before diving into it.
Awesome! I think this could be entirely implemented during a permission tree generation step. Perhaps this is of help to you π
Looking forward to your PR π
cmiiw, if we translate that way.
For something like this
const permissions = shield({
User: and(isAuthenticated, {
name: or(isAdmin, isEditor),
email: isAdmin,
},
})
would translate to
const permissions = shield({
User: {
name: and(isAuthenticated, or(isAdmin, isEditor)),
email: and(isAuthenticated, isAdmin),
}
})
Therefore it will return
{"user": {"name": null, "email": null}}
instead of
{"user": null}
is it right?
Hey @luhagel π ,
Thank you for opening the issue. I had a similar idea a long time ago that would allow us to use
and
,or
, and other logical patterns on dictionaries as well as rules. In the case of dictionaries, we would simply merge the rules at the lower level.For example,
const permissions = shield({ Query: and(isAuthenticated, { fruits: or(isAdmin, isEditor), customers: isAdmin, }, })would translate to
const permissions = shield({ Query: { fruits: and(isAuthenticated, or(isAdmin, isEditor)), customers: and(isAuthenticated, isAdmin), } })Is that what you had in mind?
It's one of the last things that I think are truly missing from the library alongside
race
rule (#645).I am sad to say this, but since this library lost its funding, I am not sure when I'll find time to implement these features.
Not exactly. I mean it depends on your schema, not your permissions.
If one of your fields (let's say email
) were required in User
and the email-resolver returned null
, you'd get
{ "user": null }
If email
were an optional field, however, you'd get
{ "user": { "name": null, "email": null } }