prisma / prisma1

💾 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL & MongoDB) [deprecated]
https://v1.prisma.io/docs/
Apache License 2.0
16.55k stars 863 forks source link

Field level permissions #1768

Closed LawJolla closed 6 years ago

LawJolla commented 6 years ago

I love Prisma! Thanks for everyone's hard work.

I searched the issues for this request -- forgive me if I didn't find it and am duplicating.

One of Prisma's big show stoppers, for me, is a lack of field level permissions.

For instance, say that I have a store with:

type Product {
 ...
  salesPrice: Float
  ourCost: Float
}

I want the ability to resolve the field ourCost based on authorization rules. e.g...

// unauthorized request
data: { product: {salesPrice: 10.00, ourCost: null} }
// authorized request
data: { product: {salesPrice: 10.00, ourCost: 5.00 } }

In a typical GraphQL server, I would be able to set a resolver specifically for ourCost.

But without Prisma giving a field level permission, I either need duplicate types, e.g. type Product {} ... type ProtectedProduct or make some kind of crazy wrapper that'll take db.Product({...}), run it through a permission object, and return the above structures.

lunchboxer commented 6 years ago

You might check out Vulcan.js, which has a rather simple permissions system which handles type and field level permissions

LawJolla commented 6 years ago

Thanks for the suggestion. I think Sasha and MDG do a great job, but I like Prisma / Graphcool and am not interested in the Meteor pond.

lunchboxer commented 6 years ago

I'm not advocating using Vulcan instead of Prisma. Rather, I think it could be informative to check out their implementation of the feature you are requesting.

LawJolla commented 6 years ago

@lunchboxer understood, thank you. It's a good system, but given its coupling to Meteor, I'm not sure how Prisma could implement it in a more generic way (opinionated codebases certainly have advantages!).

For those looking in, Vulcan has field-level options, e.g.

postedAt: {
  type: Date,
  optional: true,
  insertableBy: Users.isAdmin,
  editableBy: Users.isAdmin,
  publish: true,
  control: "datetime",
  group: {
    name: "admin",
    label: "Admin Options",
    order: 2
  }
}

http://docs.vulcanjs.org/schema-properties.html#viewableBy

It's able to do Users.isAdmin from its dependence on Meteor user account. Perhaps Prisma could specify a function name, inject the context, and the developer returns a boolean?

maticzav commented 6 years ago

Have you tried implementing a small type resolver, which would check authorization-required fields and return null if no user is authenticated? Something like this:

// Product.ts
import { getUserId } from './utils'

export const Product = {
   ourCost: async (parent, args, ctx, info) => {
      const userId = getUserId(ctx)
      if (userId) {
         return parent.ourCost
      }
      return null
   }
}
LawJolla commented 6 years ago

@maticzav I hadn't... I'm not new to GraphQL, but I am behind the curve on schema stitching. Just this weekend I looked at the airbnb example where types lived in the top level, along side Query/Mutation/Subscription -- that was confusing.

But I'm starting to get it, and I tried your suggestion and it (of coursed) worked! And works well. There may be a more elegant solution that those above my pay grade can deliver, but I'm content with this solution for now. Thank you for the great suggestion!

lastmjs commented 6 years ago

Hopefully directive permissions will be considered here.

https://blog.graph.cool/graphql-directive-permissions-authorization-made-easy-54c076b5368e

https://medium.com/@lastmjs/advanced-graphql-directive-permissions-with-prisma-fdee6f846044