I'm working on an MVC application with this structure:
Request
V
FrontController <-> Router
V
Controller <-> Model
V
View
I have two other components that I need to place in this structure:
Authentification
: Logs the user in using the $_SESSION
global variable;RBAC
: Role Based Access Control that can check if a role has access granted to a "ressource" (Controller
method).Every users can have any given number of roles (they can also have none).
Now, I need to place those two components in my applications, I need them to be able to:
User
isn't authed and that the Request
requires a authed User
to be executed, the client should be redirected to a login page;RBAC
sees that the authed User
doesn't have a role that has access granted to the required "ressource" to execute the Controller
's method, the Controller
's method should still be executed but with knowledge that the User
did not have the permission to do so (Example: A User
writes an article but doesn't have the right to publish it, so the article is saved as a draft and the User
is told that a Moderator
will have to publish it).I already have a few ideas where to locate the Authentification
and RBAC
but I'm not sure:
Authentification
could go in the FrontController
or the Router
;RBAC
could go in the FrontController
or the Controller
.I saw someone putting the RBAC
in the model but I don't understand why.
I'd like to have some insight on the subject please. Where should I put the Authentification
and RBAC
components?
Thank you!
In my experience, access control business logic changes as new features are added, so it pays to design flexibility and motility into your access control system. Thus, I would engineer Authentication and RBAC as separate traits, then incorporate those traits into the controller space as necessary.
As described, it sounds like the authentication trait would best be incorporated into your front controller: you know that all dependent controllers require authentication, so incorporate that check early in the life cycle to free up request sockets. If your requirements ever change to need some controllers to be ungated, you can push the trait down into specific controllers or into a base controller class.
As for RBAC, that may apply globally to all controllers as well as locally to some controllers. For example, your FrontController may query the RBAC to build the routing table, while dependent controllers would use the RBAC for their specific needs.
One thing to consider, though: you may also have some RBAC needs in the model. That is, some roles may have limited access to some fields in some models: role A can access all of model X, but role B can only read fields 1, 2, and 3 of model X. (Trust me, I have seen very, very complicated rules around roles that can see and act on what fields.)
Engineering RBAC as a controller trait may make porting to model space difficult. Thus, you may find it better to engineer RBAC as a service delegate and inject it on demand. With a well-provisioned IoC container, a service delegate is just as easy as compile-time traiting.
Finally, I'll add that you're going to want both of these under heavy test (they are important, after all). So whatever you choose, engineer so they can be tested. In my opinion, both traits and delegates are easy to test in isolation and either would be a good choice for implementing the necessary logic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With