Two weeks ago, I mentioned an easy way to create easily changeable ways for authenticating users. Continuing on that, I’ve been implementing ways to control user roles and user access for specific pages and modules in my CMS. Naturally, those features too are designed to be easily modifiable.
- An ACL factory
- A RoleProvider singleton
You might not know what those two do yet, but let me explain…
The general structure
Let’s first take a quick look at the general way the classes interact with each other.
- The authentication adapter factory is used for authenticating the user.
- The ACL factory constructs a Zend_Acl object from the roles and the page being opened
- The role provider’s job is to provide the ACL factory (and any other components) with the available roles, and the user’s roles
In addition, there’s a class which does all the above before a page is loaded: it loads the user, builds an ACL based on that and checks if the user has access or not.
You might ask “why all these? can’t you just use a database?”
While the answer to that is “yes, I could”, the thing is that often some database-backed access system may be overkill for a simple project. Other times you might need to use different ways of seeing which user is supposed to access which page. For example, you might want to have users in groups and use groups to determine their access, or you might simply want to define access on a per-user basis.
Both the role provider and the acl factory are created once in app bootstrap and stored as singletons.
The ACL factory
The ACL factory builds ACL objects that can be used to check if a user has access to a specific page or not.
The usual implementation of ACL in Zend Framework related guides and such seem to be to build an ACL with every resource and every role and use that. But what if your site has a thousand pages? It could get very memory-hungry in a very short time.
The ACL factory combats this by only containing the absolutely required things: The user’s roles and how they inherit each other and the page’s ID and privileges. Nothing else is required to determine if the user can access the specific page, so nothing else is loaded.
The ACL factory does not know what roles the user has, nor what the available roles are. It queries the RoleProvider for those. This component can be swapped to create different kinds of ACL’s if necessary.
The RoleProvider is one of the parts that make the system easy to modify.
In this version, the role provider’s job is to list all available roles and to get a user’s roles. For example, I have a User RoleProvider, which lists all users in the database as roles, allowing me to specify page access for each user separately. I also have a Group RoleProvider, which lists groups in the database as roles, allowing me to specify page access for each user group.
In the CMS admin panel, the role provider is used to list all the roles available for pages, so that the user can define which roles have access to the pages.
The whole package
There are still some matters that need to be dealt with, but this system works quite well and does what I want: it is very easily changeable to work in a different way for a different project.
If you have any ideas of your own, or opinions on my approach, feel free to share, as always.