Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RLS #1

Open
jiashengguo opened this issue Mar 9, 2023 · 0 comments
Open

RLS #1

jiashengguo opened this issue Mar 9, 2023 · 0 comments

Comments

@jiashengguo
Copy link
Member

jiashengguo commented Mar 9, 2023

The Prisma extension library ZenStack we are building happens to share the same view with wladiston andLiam-Tait’s solution to use the schema as the single source of truth. 🤝

This is how the sample schema should be represented in ZenStack now:

enum Role {
    USER
    ADMIN
}

model Cart {
    id String @id @default(uuid())
    customer Profile @relation(fields: [customerId], references: [id])
    customerId String

    //Carts are only visible by owners
    @@allow('read', customerId == auth().id)

    //Admins can do anything with carts
    @@allow('all', auth().role == 'ADMIN')
}

The only differences are:

  1. We use @@Allow and @@deny instead of @@security
  2. We don’t generate RLS for now. Instead, we add a transparent proxy on Prisma client.

For the multitenancy issues, we invited a Collection Predict Expression to express it. Here is how it looks now:

enum Role {
    USER
    ADMIN
}

model User {
    id            String    @id @default(cuid())
    spaces SpaceUser[]
    
    // can be created by anyone, even not logged in
    @@allow('create', true)

    // can be read by users sharing any space
    @@allow('read', spaces?[space.members?[user == auth()]])

    // full access by oneself
    @@allow('all', auth() == this)
}

model Space {
    id String @id @default(uuid())
    members SpaceUser[]

    // require login
    @@deny('all', auth() == null)

    // everyone can create a space
    @@allow('create', true)

    // any user in the space can read the space
    @@allow('read', members?[user == auth()])

    // space admin can update and delete
    @@allow('update,delete', members?[user == auth() && role == ADMIN])
}

/*
 * Model representing membership of a user in a space
 */
model SpaceUser {
    id String @id @default(uuid())
    space Space @relation(fields:[spaceId], references: [id], onDelete: Cascade)
    spaceId String
    user User @relation(fields: [userId], references: [id], onDelete: Cascade)
    userId String
    role Role

    // require login
    @@deny('all', auth() == null)

    // space admin can create/update/delete
    @@allow('create,update,delete', space.members?[user == auth() && role == ADMIN])

    // user can read entries for spaces which he's a member of
    @@allow('read', space.members?[user == auth()])
}

If you feel interested, there is a tutorial post I wrote about it:

How to build a collaborative SaaS product using Next.js and ZenStack's access control policy

We would really appreciate it if you could share your opinions by commenting or joining our Discord to help us make ZenStack the right thing to solve your problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant