-
Notifications
You must be signed in to change notification settings - Fork 23
Description
This is something I had attempted the oft-mentioned original version of this library, but it ended up very very cumbersome and error prone--I'm not sure this will be practical
The "Dream" of JSONAPI.EntityFramework.Http.ApiController and really of JSONAPI.Http.ApiController and IMaterializer is to be able to provide an almost completely canned JSON API compliant service broker--all you have to do is to override/implement a few interface points to integrate with your persistence layer and you're done. However, especially in the case of the EF ApiController, this has turned out to be more pipe dream so far, as I usually have to override the verb methods and it's hard to reuse the super-method.
One of the main reasons I find myself having to throw away the default verb implementations (particularly Put, Post, and Delete is to insert authorization controls, for example to make sure users can only edit their own records. Additionally, I often need to control things at the property level, e.g. a user can't change the Owner of a record to someone else (but an admin user may be able to do this).
In the current architecture, the separation of the deserialization from the IMaterializer provides a good place to inject a reusable authorization layer. We could add an IAuthorizationProvider property to the IMaterializer, and have some API for the IMaterializer to ask the IAuthorizationProvider whether any given property update should be allowed. This in theory would be good from a separation of concerns perspective, because it would encourage encapsulation of security logic from other business logic.
Gotchas (from previous experience):
- My previous attempt at this involved a bunch of attributes on model classes and properties, the goals of which were to define the default behavior from which to allow overrides (think Apache's
Order Deny,Allow; Deny from All). This sounded good, but led to the definition of more exceptions than rules--possibly not the best way to go. - Sometimes separation of the authorization logic from the business logic was a bad thing. Specifically, if both authorization decisions and other business logic depended on making the same expensive calculation--I'd find myself pushed into making the calculation twice.
- My earlier attempt also provided separate tiers of control for the object and the property, with callbacks that could be defined to allow/deny access to read/modify the object, and then also to allow/deny read/write access to the property. This theoretically would improve performance--if the user was denied writes to the object, there was no need to make callbacks to ask about the properties. In practice though, this led again to a lot of duplication of logic and computation because the same queries or calculations had to be made in both tiers.