Application design hurdles with dependency injection #1264
justin-hackin
started this conversation in
General
Replies: 2 comments 3 replies
-
I'm also confused about authentication flow with the user creation process. Zenstack provides automatic password hashing but you need a user in order to enhance prisma so that feels like a 🐓 & 🥚 problem. If I try to pass in a mock user with just an id, zenstack complains that it doesn't have the attributes it needs on the auth() for the rules. |
Beta Was this translation helpful? Give feedback.
2 replies
-
Here's the preliminary pattern I used for anyone interested (correction: it's function overloading not type refinement): EDIT: my previous snippet TS was a little broken and not succinct enough, updated export async function resolveAuthedResources(): Promise<{
zPrisma: PrismaClient;
}>;
export async function resolveAuthedResources(
request: Request,
): Promise<{ zPrisma: PrismaClient; user: BasicUser }>;
export async function resolveAuthedResources(request?: any): Promise<any> {
if (request) {
const authUser = await authenticator.isAuthenticated(request, {
failureRedirect: ROUTES.LOGIN,
});
if (!authUser) {
throw redirect(ROUTES.LOGIN);
}
const user = await getUserById(authUser.id);
if (!user) {
throw redirect(ROUTES.LOGIN);
}
// can't use the cookie value which doesn't update on admin changes
const zPrisma = await getEnhancedPrismaClient(user);
return { user: authUser, zPrisma };
}
return { zPrisma: getEnhancedPrismaClient() };
} |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I'm really excited about enforcing access policies on the level of the ORM. I think using zenstack is going to be a big win for my project and I'm really thankful that you provided some tutorials about remix integration. That being said, I found myself thrashing around a lot on how to redesign my API interfaces after introducing zenstack to my prisma/remix project.
Since all enhancement requires a user, at first I thought I would just put a
currentUserId
into every prisma helper function and pass{ user: {id: userId}}
as the context forenhance
as I saw in examples. However, I discovered that this is not suitable for my app because I need the whole user record to enforce access. I thought that maybe zenstack would be fetching the record behind the scenes since it knows the user table but that is not the case but... 🤦♂️ it wouldn't know which properties to include.For now, I am using
remix-auth
with a form strategy and so I need access to aRequest
instance in order to first check that the session is valid before any prisma requests. From the cookie, I get the user id, and then I can look up the user record with all the data needed for access control. I guessed that meant pushing the auth checks way down into every api helper function. That felt a tad bit inelegant but safer.Considering this, I replaced the
currentUserId
I was passing to all the prisma helper functions with theRequest
instance from loaders/actions. Then I built a functionresolveAuthedResources
to accept the request as a parameter which resolves both the enhanced client and the user record for convenience and used it in all my prisma helper functions.However, I encountered a couple issues with this approach:
auth()
but if I make the resolved user possibly undefined then I have to put existence checks everywhere that usesresolveAuthedResources
which seems yucky.Now I am resigning myself to the approach where I pass a
PrismaClient
into all my helper functions. This way I can use the db functions in my seed script or for testing and I won't have to mock out myauthenticator.isAuthenticated
calls.I'm not entirely satisfied with this approach because it doesn't protect the developer from accidentally passing in a non-enhanced prisma client and thus inadvertently circumventing access control. Hopefully the parameter name
zPrisma
at least gives a hint.I am curious to know what the community thinks about all these approaches. Do you have a better idea about how to manage an enhanced client into a SSR-based frameworks like Remix.js and NextJs? If, so I would be greatful for your feedback!
Beta Was this translation helpful? Give feedback.
All reactions