zenstackhq / zenstack

Fullstack TypeScript toolkit that enhances Prisma ORM with flexible Authorization layer for RBAC/ABAC/PBAC/ReBAC, offering auto-generated type-safe APIs and frontend hooks.
https://zenstack.dev
MIT License
2.07k stars 88 forks source link

[Documentation] Clearer description about how `auth()` works and the fact that user needs to provide all its fields #402

Closed ymc9 closed 10 months ago

ymc9 commented 1 year ago
image
lucastiburcio commented 1 year ago

How? I couldn't use it with role. @@allow('update', auth().role == 'ADMIN') didn't work.

model User {
  id String @id @default(cuid())
  name String?
  email String? @unique
  emailVerified DateTime?
  password String @password @omit
  image String?
  role String @default('ADMIN')
  ...
  }
ymc9 commented 1 year ago

How? I couldn't use it with role. @@allow('update', auth().role == 'ADMIN') didn't work.

model User {
  id String @id @default(cuid())
  name String?
  email String? @unique
  emailVerified DateTime?
  password String @password @omit
  image String?
  role String @default('ADMIN')
  ...
  }

Hi @lucastiburcio , at runtime the result of auth() call is basically the user object you passed into the context when calling withPresets or withPolicy. There you can do a database query or anything to enrich the object before passing in.

Here's an example (with Next.js):

import type { User } from '@prisma/client';
import { withPresets } from '@zenstackhq/runtime';
import type { GetServerSidePropsContext } from 'next';
import { getServerAuthSession } from './auth';
import { prisma } from './db';

export async function getEnhancedPrisma(ctx: {
    req: GetServerSidePropsContext['req'];
    res: GetServerSidePropsContext['res'];
}) {
    const session = await getServerAuthSession(ctx);
    let user: User | undefined;
    if (session?.user) {
        user = await prisma.user.findUniqueOrThrow({ where: { id: session.user.id } });
    }
    return withPresets(prisma, { user });
}
lucastiburcio commented 1 year ago

Now it worked. Thanks for the tip!!!

ymc9 commented 1 year ago

Cool! I'll improve the documentation soon ...

jasonmacdonald commented 11 months ago

@ymc9 Is there any way to NOT have Auth use the User model? In our existing system, User is not where things like Role are stored. That's on a Membership table instead. It won't let me reference that in Auth() as the User to Membership relationship is a one-to-many. :( Is there a way we could specify what Model Auth() type checks against? Forcing it to be User is constraining users DB design.

ymc9 commented 11 months ago

Hi @jasonmacdonald , yes, I totally agree there should be more flexibility. I'm thinking about using a @@auth attribute to annotate the model that one wants to use to map to auth(). How does this sound to you?

@ymc9 Is there any way to NOT have Auth use the User model? In our existing system, User is not where things like Role are stored. That's on a Membership table instead. It won't let me reference that in Auth() as the User to Membership relationship is a one-to-many. :( Is there a way we could specify what Model Auth() type checks against? Forcing it to be User is constraining users DB design.

jasonmacdonald commented 11 months ago

Hi @jasonmacdonald , yes, I totally agree there should be more flexibility. I'm thinking about using a @@auth attribute to annotate the model that one wants to use to map to auth(). How does this sound to you?

@ymc9 Is there any way to NOT have Auth use the User model? In our existing system, User is not where things like Role are stored. That's on a Membership table instead. It won't let me reference that in Auth() as the User to Membership relationship is a one-to-many. :( Is there a way we could specify what Model Auth() type checks against? Forcing it to be User is constraining users DB design.

Sounds like a great solution. Anything I could do to help?

ymc9 commented 11 months ago

Hi @jasonmacdonald , yes, I totally agree there should be more flexibility. I'm thinking about using a @@auth attribute to annotate the model that one wants to use to map to auth(). How does this sound to you?

@ymc9 Is there any way to NOT have Auth use the User model? In our existing system, User is not where things like Role are stored. That's on a Membership table instead. It won't let me reference that in Auth() as the User to Membership relationship is a one-to-many. :( Is there a way we could specify what Model Auth() type checks against? Forcing it to be User is constraining users DB design.

Sounds like a great solution. Anything I could do to help?

I've created a feature request here and marked it for the next "v1.2" release:

https://github.com/zenstackhq/zenstack/issues/774

I believe the changes needed are relatively small, but probably some local refactor is needed to consolidate logic where "User" is hard-coded. Let me know if you're interested in and have time to contribute code, and I'll really appreciate and be happy to facilitate. Either way, I'll make sure it lands in the next release 😄.

jasonmacdonald commented 11 months ago

Hi @jasonmacdonald , yes, I totally agree there should be more flexibility. I'm thinking about using a @@auth attribute to annotate the model that one wants to use to map to auth(). How does this sound to you?

@ymc9 Is there any way to NOT have Auth use the User model? In our existing system, User is not where things like Role are stored. That's on a Membership table instead. It won't let me reference that in Auth() as the User to Membership relationship is a one-to-many. :( Is there a way we could specify what Model Auth() type checks against? Forcing it to be User is constraining users DB design.

Sounds like a great solution. Anything I could do to help?

I've created a feature request here and marked it for the next "v1.2" release:

774

I believe the changes needed are relatively small, but probably some local refactor is needed to consolidate logic where "User" is hard-coded. Let me know if you're interested in and have time to contribute code, and I'll really appreciate and be happy to facilitate. Either way, I'll make sure it lands in the next release 😄.

I'll see what I can manage. :) I assume most of the changes would be in the VScode extension, since the runtime just accepts whatever context data matches, correct?

ymc9 commented 11 months ago

The "@@auth" attribute can be declared in "stdlib.zmodel". With that the VSCode should already work I believe.

Two other things are:

If you'd like to make a PR it doesn't need to be complete. I can help make it more complete. Thanks!

jasonmacdonald commented 11 months ago

@ymc9 It's by no means done yet, but I've created a PR to check if I'm on the right track. https://github.com/zenstackhq/zenstack/pull/787

ymc9 commented 11 months ago

@ymc9 It's by no means done yet, but I've created a PR to check if I'm on the right track. #787

Awesome! Thanks a lot and I'll follow up over there @jasonmacdonald

ymc9 commented 10 months ago

New docs contain more explanation about the requirements to giving all fields needed in auth(). Closing.