I'm building a combined management interface for various website components (newsletters, contact/feedback forms, …) which should be available to all of them through a single management-instance. As using a dedicated application per website is tedious and involves additional drawbacks, I've made the routing and models site-aware (i.e. /newsletter/www.my.site.com/list). While this part works like a charm, I'm somewhat stuck for implementing access control.
Unless I'm mistaken, it looks like RBAC is geared towards single-instance access control and can't easily be made multi-site aware, as I'd need ("username", "website") pairs for identification rather than the "username" avaiblable in CAuthManager.
One possible option would be modifying the AuthManager to accept one or more additional parameters in order to filter the items (like changing the $userId to an array, with a possible convention that a field not filled-in is ignored). Before undertaking this task, I'd like to hear the opinions of other people or whether someone already did such changes.
Another (doable?) way would be the use of database views to avoid the above coding and have the DB do the hard work. Unfortunately I'm not quite sure how to manage the inserts/updates in that scenario. Furthermore, it'd be heavily database-dependent as not every RDBMS supports writeable views.
Or did I miss another solution that works out-of-the-box?
Yes, but not quite (or, said differently: not in a single call to checkAccess() ). It is indeed an elegant solution to manage strictly separate accesses to the different site but doesn't allow global access to all of the sites, achievable by ignoring some of the filters if they aren't set in the auth backend.
I cant't really agree with your proposed approach.
The business rules shouldn't serve this purpose but rather be kept for more useful tests, such as the "updateOwnPost" task from the documentation. Yes, bizRules can be defined at any level, but the one place I'd be adding it to may require another snippet at some time. Not good. I don't want to micro-manage code generation when assigning roles to users: merging code snippets is going to be a maintenance nightmare I'm readily avoiding as much as possible.
Furthermore, this kind of filtering should be done by the database. After all, the information required to figure out whether a user may access a given resource or not will be present inside the AuthAssignment table in either case (be it serialized inside the data or in a dedicated column). No need to fetch the row and evaluate some PHP code in order to come to the same conclusion than the database would knows right away.
The RBAC overhead is already quite big in my case (7-15 queries for the menus alone). I don't want to trigger a PHP code evaluation for most of these rows. For that same reason, I'd avoid executing checkAccess() twice (once with the domain suffix and once without). It just wouldn't scale and can't be done with numeric userId's.
So, I guess I'm going to try my initial idea and modify the first few methods of CDbAuthManager and add dynamic filtering, although I fear it's going to be quite a mess.