Building can? function that supports filter checks

I am looking to build out a custom GQL query that allows my front-end to ask the backend whether it has permissions to do an action on a resource instance. I have already built this out to a resource level to the extent that the front-end can ask: "Can I perform this action on this resource type". Next up, I want to support asking "can I perform this action on this particular resource with ID = x". @frankdugan3 already added some canfunctions, which I am using in the above scenario. However I will need extra functionality so that in addition, the filter checks are taken into account. The reason is that some of my action policies use relates_to_actor_via. For the reads I suppose I could actually perform the read and use the result. However for :update there are also filter checks and I can't use that strategy. Any thoughts on how best to approach this? I have started looking into it however quickly got lost in the engine / request modules.
11 Replies
ZachDaniel
ZachDaniel•3y ago
Hey there! So I have something on my list to make this kind of thing work too, but it will take a bit of elbow grease potentially.
Alan Heywood
Alan HeywoodOP•3y ago
Hey Zach! Sounds intriguing :thinkies:
ZachDaniel
ZachDaniel•3y ago
GitHub
ash/info.ex at main · ash-project/ash
A declarative and extensible framework for building Elixir applications. - ash/info.ex at main · ash-project/ash
ZachDaniel
ZachDaniel•3y ago
So the essential gist is going to be getting the {:filter back, and then running a query with that filter to see if we get the record that we're attempting to update. For creates that won't really work but for updates/destroys, it will I think thats the main avenue we need to pursue
Alan Heywood
Alan HeywoodOP•3y ago
Creates I am not too concerned about, I think creates should always use simple checks. How would the above strategy work for updates?
ZachDaniel
ZachDaniel•3y ago
What you'd do is run the filter, combined with a filter on the id of the current record you're trying to update if you get the record back, then it will be allowed if you don't then it won't
Alan Heywood
Alan HeywoodOP•3y ago
Oh yeah, that makes sense. Thanks!
ZachDaniel
ZachDaniel•3y ago
Same can work for destroy 😄
Alan Heywood
Alan HeywoodOP•3y ago
With your guidance I was able to get this working 🥳 I'm not confident it's ready for integration into ash core, so i'll post it here in case anyone else finds it useful: https://gist.github.com/ahey/61238fdc367175589fa90431318705c9 @Zach Daniel while developing this, I found that the following code (https://github.com/ash-project/ash/blob/main/lib/ash/policy/info.ex#L36) was preventing this call (https://github.com/ash-project/ash/blob/main/lib/ash/policy/info.ex#L44) from ever returning {:filter. Once i change pre_flight_authorization? to false it started working, however i'm not sure why :thinkies:
ZachDaniel
ZachDaniel•3y ago
Interesting…I think inside of filter check if preflight authorization is being run and we attach a filter we may not be returning the filter? Hey @Alan Heywood I've added a version of this built into core now. The latest version has YourApi.can? and YourApi.can
Alan Heywood
Alan HeywoodOP•3y ago
Wonderful! I'll see if I can swap over to it from my implementation. Thanks Zach 🤩 The new can? function is great. I was able to swap it out with my implementation and all tests are passing. It does everything I would want it to do and more. Thanks again @Zach Daniel 😄

Did you find this page helpful?