-
Hi, I use CASL for authorization. To be precise, I use its prisma integration which allows me to specify permissions based on my database structure like this: export const defineAbilitiesForConference = (
session: Session,
{ can }: AbilityBuilder<AppAbility>,
) => {
if (session.data?.loggedIn && session.data.user) {
const user = session.data.user;
can("create", "Conference");
can(["list", "read"], "Conference", {
OR: [
{ members: { some: { user: { id: user.id } } } },
{
committees: {
some: { members: { some: { user: { id: user.id } } } },
},
},
],
});
can(["update", "delete"], "Conference", {
members: { some: { user: { id: user.id }, role: "ADMIN" } },
});
}
}; Coming from a simple REST api I simply injected the api.get(
"/conference",
({ permissions }) =>
db.conference.findMany({
where: permissions.allowDatabaseAccessTo("list").Conference,
}),
{
detail: {
description: "Get all conferences",
},
},
) this works pretty nice since I simply can declaratively specify which entities are accessible/readable/listable etc. under which specific conditions. builder.prismaObject("Conference", {
fields: (t) => ({
id: t.exposeID("id"),
name: t.exposeString("name"),
committees: t.relation("committees"),
}),
});
builder.prismaObject("Committee", {
fields: (t) => ({
id: t.exposeID("id"),
name: t.exposeString("name"),
members: t.relation("members"), // I'll omit further definitions from this point on since it's tightly related with various tables
}),
});
builder.queryType({
fields: (t) => ({
findConferences: t.prismaField({
type: ["Conference"],
resolve: async (query, root, args, ctx, info) => {
// if I'd like to adjust the args for more filters, I'd add them here
args.where = ctx.permissions.allowDatabaseAccessTo("list").Conference;
return db.conference.findMany({
...query,
});
},
}),
}),
}); And this works fine, as long as I only look at the non relations. So conferences the user does not have access to are filtered out just as I expect it to. query {
findConferences {
name
committees{
name
}
}
} the database query obviously just returns all entries which are related. So now to my question: How can I elegantly run the permission filter/checks for relation queries? Do you have an easily comprehensible example for a scenario similar to mine? Or just some general advice on API structure/design which I can follow to tackle this? I need something similar to the Thank you so much for your time and work! |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
I don't have any experience working with CASL, but the scope auth plugin is probably a good place to start: https://pothos-graphql.dev/docs/plugins/scope-auth I think your idea of filtering down inside the queries is good, I've do that in a lot of the APIs I've worked on. For filtering nested relations, the |
Beta Was this translation helpful? Give feedback.
-
@m1212e Try and use the CASL Prisma function called |
Beta Was this translation helpful? Give feedback.
I don't have any experience working with CASL, but the scope auth plugin is probably a good place to start: https://pothos-graphql.dev/docs/plugins/scope-auth
I think your idea of filtering down inside the queries is good, I've do that in a lot of the APIs I've worked on.
For filtering nested relations, the
t.relation
method can take aquery
option that can use, as long as you can generate the query syncronously, eg:t.relation('committees', { query: (args, context) => ({ where: ctx.permissions.allowDatabaseAccessTo("list").Committee }) })