Hi, I'm fairly new to using Neo4j and the companion lib to build GQL APIs, I do love the concept and how easy it is to define complex queries right in the schema.
However I've been searching for a long time now, how to implement a fairly common pattern in web apps, where your users have their own data and shouldn't be able to access other users data, but you also have admin users who can access everything.
For example, let's say we have an e-commerce dashboard where people can manage their orders, products, etc... Each user has their own dashboard with only their own data. In addition to that, I want to have a global admin, that can for example give statistics about all data across users.
I found I can achieve the user owned data part with @additionalLabels
, that works great, but the problem is now I can't give access to everything to an admin user. The only way I see is rewriting every query and mutation as a cypher query that ignores labels. That's not ideal.
I'm also not sure how to write @cypher
queries that respect this labeling, for example
type Category @additionalLabels(labels: ["user_<%= $cypherParams.userId %>"]) {
categoryID: ID! @id
categoryName: String
description: String
grossProfit: Float! @cypher(statement: """
MATCH (this)<-[:PART_OF]-(p:Product)<-[r:ORDERS]-(o:Order)
WHERE 'user_' + $cypherParams.userId IN labels(p) AND 'user_' + $cypherParams.userId IN labels(o)
RETURN SUM(r.quantity * toFloat(r.unitPrice))
""")
}
For some reason, this always returns 0, I am sure that $cypherParams.userId
is set to 5 in my context and the label on my nodes is user_5
, and the query works fine without the WHERE
clause.
I'm also able to make this query work in neo4j browser if I replace $cypherParams.userId
with 5, then it gives me the correct result.
EDIT: I found out that when you pass the number 5
as param it is converted to 5.0
as a string by default so the solution is to do toInteger($cypherParams.userId)
instead.
So I'm at a point where my user's data is correctly segmented and accessible only to their owners but now I don't know how to bypass it for users that have admin roles.
Is there a way to achieve this kind of access control with neo4j-graphql-js
?
And if not, is there a way to create custom directives to achieve this ?