I'm in need of access control (per field and per collection) that is based on the collection item's originalDoc.
I have a collection Posts
where any logged in user can create
a Post
. However User
should be able to read
, update
and delete
only his own Post
.
There should be also possible to restrict certain fields that would be editable only by system or admins, not Users.
I have implemented a relationship field owner
, relatedTo Users. I used afterChange (operation===create)
on Post to fill the value automatically by the system.
Now I need to write an access functions that will resolve true only if user.id === doc.owner. I stuck here as access functions don't pass doc data.
I tried to leverage different hooks but it feels hacky and I got inconsistent or weird results.
With read op for example filtering out not-owned items in Posts
with beforeRead query returns totalDocs of all Posts in the system and lists all posts, just those not-owned are null
.
With update op I didn't even find a combination of hooks that would make such access control possible (even if there is any it feels like wrong unmaintainable approach).
I understand that current access implementation is only for controlling access in whole collection based on user and input data. Any suggestions how to go about this? If this is not currently possible, would it make sense to introduce such features?
Hey @chladog — question for you.
When you say:
Now I need to write an access functions that will resolve true only if user.id === doc.owner. I stuck here as access functions don't pass doc data.
Do you want to use field hooks, or collection-level hooks here?
If collection level, this is actually super easy. In access control, you can return a query constraint
to restrict which documents that a user can perform actions against.
Here's an example of how we would normally do something like this:
const adminOwnerAccess = ({ req: { user } }) => {
// If user is admin, return true
if (user && user.roles.includes('admin')) {
return true;
}
// If there is a user, return a query constraint
// that only allows users to perform actions against
// documents where the owner is equal to their user ID
if (user) {
return {
owner: {
equals: user.id,
},
};
}
// If neither of the above conditions are met,
// Block access
return false;
};
Is this what you need? Note, we might need to expand on our docs if you didn't see that this is possible via documentation. It's one of the strongest features of our access control!
oh, right! I even had it implemented similiary in other collection already facepalm.
Though how to implement same logic with FieldAccess?
My collection has following structure:
{
owner: User
editors: User[],
someData: {
...
}
Required behavior is that User who is an Owner or one of the Editors can update the document (solved already by query constraint).
But only Owner can change Owner and Editors field.
Editor can change everything except Owner and Editors.
OK I just released payload@0.14.30-beta.0
which now includes doc
in the field access function arguments for both read
and update
operations.
You can read whatever you want off that original doc. But note that the doc
is only available in read
and update
operations, as there will be no doc
in create
. There, you'll need to check the incoming data
property due to the document just recently having been created.
How's that? Give it a shot!
Working like a charm. Perfect, thank you!
Star
Discord
online
Get help straight from the Payload team with an Enterprise License.