Roles & Permissions
Marblism uses ZenStack to implement a powerful and flexible permission system. This system is based on the auth()
function and @@allow
decorators in your Zenstack data model.
Understanding auth()
The auth()
function represents the currently authenticated user. It allows you to reference the current user's properties in your permission rules.
Using @@allow
Decorators
The @@allow
decorators define access rules for your models. They take two arguments:
- The operation type ("create", "read", "update", "delete", or "all")
- A boolean expression that determines if the operation is allowed
Here's an example from the User model:
model User {
// ... other fields ...
@@allow("all", auth().id == this.id)
@@allow('all', auth().globalRole == 'ADMIN')
@@allow("create", globalRole != 'ADMIN')
@@allow("read", true)
}
Let's break down these rules:
@@allow("all", auth().id == this.id)
: Allows users to perform all operations on their own record@@allow('all', auth().globalRole == 'ADMIN')
: Allows admins to perform all operations on any user record@@allow("create", globalRole != 'ADMIN')
: Allows any user to create non-admin users@@allow("read", true)
: Allows any user to read information of all user records
Protecting Other Models
To protect other models, you can use similar @@allow
decorators. For example:
model Post {
id String @id @default(uuid())
title String
content String
authorId String
author User @relation(fields: [authorId], references: [id])
@@allow('all', auth().id == authorId)
@@allow('read', true)
}
This setup:
- Allows users to create, update, and delete their own posts
- Allows anyone to read posts
Remember to always start with the most restrictive permissions and then add exceptions as needed.
Best Practices
- Be explicit about your permissions
- Use
auth().id
to reference the current user - Consider using roles for more complex permission structures
- Test your permissions thoroughly to ensure they work as expected
By understanding and properly implementing these concepts, you can create a secure and flexible permission system for your application.
Automatic Permission Application
It's important to note that these permissions are automatically applied when using the ctx.database
Prisma client. This means that when you query the database using this client, the results are automatically filtered according to the logged-in user and the permissions applied to the model.
For example, consider the following query:
const posts = await ctx.database.Post.findMany();
In this case, the findMany()
query will only return posts that the current user has permission to read, based on the rules defined in the Post model.