I’ve been toying with modernizing/restructuring the code in a website.
One of my goals was to refactor out as much generic functionality into reusable classes as possible. As such my “library/framework” folder now contains among other things some generic controller, model and template base classes which all the site specific controllers and models extend from…
So far this has worked fairly well, but recently I’ve started working on user authentication and access control and I’ve got stuck with the following dilemma:
According to my original plan the controller would internally instantiate a user object to determine the active user’s credentials and to handle access control. As this would be required across all controllers the majority of it was supposed to be happening in the base controller class with individual controllers being mostly responsible for specifying minimum requirements for access. This is where I’ve hit a snag:
The authentication etc. requires database access. As such the user class would naturally derive from the base model class but more importantly it would belong to the site specific category. This is especially true if the site requires the user table to also contain additional (site specific) data for each user…
On the other hand it would be nice for the authentication/access control to reside in the generic section, both because I may wish to reuse it in the future as well as to avoid code duplication by needing to manually instantiate the user object in each controller again and again.
To clarify the second point a bit: As mentioned above the ideal place for this seems to be (at least to me) the controller base class. But in order to satisfy the requirement for keeping the generic classes free from site specific dependencies it looks like it cannot be included there. The only alternative I can see is that each individual controller will need to include some code for initializing a user object etc…
Is there a better way?
Two bonus questions:
It occurred briefly to me keep the user class focused purely on the database manipulation and use a separate user manager class for handling the authentication. I’ve seen some code using various “manager” objects in various places, but to be honest so far I haven’t quite managed to grasp in which cases these would offer some advantages. For my example it does not seem to make any difference…
The site in question stores some additional details (e.g. extended info) about each user (referer, screen resolution etc.) It feels to me, as if some of these columns are “polluting” the users table. At least conceptually it would seem nicer to keep a separate “pure” users table with just the critical user data and another one with the (site specific) “user info” data. However since there would be a one-to-one relationship between these two tables, this would contradict database normalization guidelines. Is there a case for such separation or one should simply accept that the users table would vary from site to site?
Authentication is a userland issue: it’s not up to the framework to decide how you determine if a user is actually a user: it’s up to the application itself. User objects may vary between applications just as well. The “Identity” approach that kyberfabrikken just mentioned is a nice way to keep the identity of the user separated from the User itself, although your application still has to define what a User looks like, and how the identity of that user can be found.
How about creating an application-specific controller for each application, which does the grunt work like this. Just make sure every controller of that application inherits from the application-specific controller, and the repetition is gone just the same.
The act of authentication, the identity of a User and the User itself are different things, and they may differ between projects. Keeping them all separated gives you the benefit that you can re-use the authentication part, without needing the exact same User object. You can use the User object in the application itself, without the User having an Identity at that time: the only user that has an Identity is the one that is logged in.
Splitting the concerns up like this, makes it easier to adapt previously written code to new situations.
Normalisation, schnormalisation. I know I shouldn’t say that, as there is good logic behind the theory of normalisation. Nevertheless, the rules aren’t written in stone, and it doesn’t really hurt that much to have two tables with a one-to-one relation; it’s actually more common than you think. I don’t necessarily see the benefit of keeping the “pure” user information separated from the “unpure?” user information. After all, it’s all user information. If you do see the benefit: go for it, there is no normalisation police that will come knocking on your door.
Heres some ramblings about how I handle auth/permissions, not sure if its the best way, but you might find some of it useful
I keep my user authentication details in a separate table than site/project specific stuff.
The user table contains username, email , password and roles (comma seperated).
I can then have multiple user types e.g ‘administrator’, ‘standard member’, ‘manager’ etc each in their separate table (with user specific columns),each with a reference to the user table by ID.
This way my authentication is generic (and wrapped up in a base user class) as i’m only ever querying one table, and after login I store the logged in user into the session I can query later.
My ACL is actually in an ini file as they rarely change and DB access seems overkill (although I guess you could just cache the db call).
The ACL is made up of roles (related to user types), resources (e.g ‘admin area’, ‘blog’ etc) and ‘access’ which is is a combination of the role, resource and whether they have access to the resource (a boolean). The resources could be controllers, actions or whatever.
When I want to see if a user has access to a controller/action/whatever I have a method that loops through each of the roles in the stored user session object and compares access for the resource I pass in.
Although the method is generic, the placement of this method call is flexible as the type of roles/permissions required vary enough from project to project. Depending on the level of authentication i’ll add the check to be fired for any controller action (in a predispatch method) or from a specific action is more granularity is required.
The downside to all of this is that when creating/editng/deleting users you have to work against two tables, the role specific one and the generic user table.
This. I find it makes good sense to keep the user and the authentication as separate concerns. You might want to use the user model for other things than authentication, just as you might want to want to have different methods for authentication, perhaps even using different sources of users.
I use an architecture where there is an Identity, an IdentityLoader and possibly some kind of user model/entity behind. The Identity can be Anonymous or it can be an AuthenticatedUser (Which would then refer to a user entity). The IdentityLoader is pluggable - There can be more than one for a given application. I find that this works quite well. If you’re interested:
In fact this is exactly what I’ve ended up doing yesterday after giving this some more thought
I’ve also decided to separate the user class into a separate “UserBase” class and an application specific extended version. The UserBase only defines core fields and functionality and the extended version adds site specific stuff to it. Like this I don’t really see a pressing need to separate the database table itself. On the other hand I will give the idea of the UserManager some more thought… Should I go for that then the above mentioned separation may become unnecessary as most of the functionality in UserBase revolves around authentication…