2009年8月24日星期一

RE: [fw-mvc] RE: Acl factory the MVC way

I suppose. Strictly speaking in the most general sense, an ACL's role is for controlling access to something. Hiding links is useful as a presentation effect, but not really part of access control, since if you only hide links and don't implement true access controls, a smart hacker can probably guess your hidden links anyway.
 
With ZF there are so many ways you could go about doing this, it's hard to know where to start to suggest a solution. Specific to this topic, we are talking about dynamic ACLs, which specifically means only creating enough of the ACL based on what is being requested and who is requesting it. The concept of doing it dynamic is based on the premise that you have a very complex set of access rules (most likely stored in the database), and having a large static list is too difficult to manage or perhaps a performance problem with ZF. So you only load a subset of the full ruleset...enough to accurately determine if the current request is allowed or not.
 
To determine what links are available involves a much larger task in terms of you are also attempting to determine what access he could have to other resources that haven't been requested yet. There are two possibilities... 1) the links are global (like having an admin link in the layout), or 2) the links are view specific (like having a link to "edit" a blog post) which may not apply to the currently requested resource (maybe they are looking at their profile page, not a blog post).
 
In the former case you could extend your ACL creation a bit to also look at these other resources in order to determine what additional links to provide. In the latter case, an ACL implemented as a controller plugin is probably not the best solution for hiding links, since the number of cases to deal with is proportional to the number of view scripts in your application.
 
If you were to use the ACL in the controller plugin, you could do some checking and then you have to have a way of passing the result on to the view. Maybe you could use the session namespace to do this, or there are probably many other solutions.
 
But most likely a view helper would be the better way of doing it. Even if you used an entirely separate instance of Zend_Acl in the view helper, it would probably work out better so you can have your view specific criteria what links may or may not appear depending on where in the application they currently are.
 
The important thing is to understand what is the main criteria for having or not having a particular link. In my case, group membership is what determines which links or forms may or may not be available. I have another controller plugin which is sort of an identity handler, which simply takes the Zend_Auth result and populates a session namespace not only with the current username, but also all group memberships tied to that account. I have this in a session namespace so it is easily accessed from all locations in the app (without having to go get it from the database again and again) and I can use that info to help in creating my ACL, as well as provide dynamic view elements etc, etc.
 
I have a remaining category of links which I handle actually within the ACL, because they are context specific. In other words, some pages may have a link on them that technically the user won't have access to, or rather what they will see when they access the link depends on other criteria. What they see isn't actually determined until they click the link and the ACL checks permissions, the result of which redirects them to perhaps a different controller/action. For example, in a forums application, you might have the poster name hyperlinked. When the request is processed who clicked the link might show a private message view if the person clicking the link is not the person whose link they clicked. But if it is the same person (clicking on their own name), it might take them to their profile page. I handle this type of stuff in the ACL plugin. But the main point is, there is no dead link, which is important to the user experience.
 
Wow, another long answer! Sorry!!! I guess there are just a lot of possible answers and I got carried away.
 

--Seth

 


From: Саша Стаменковић [mailto:umpirsky@gmail.com]
Sent: Monday, August 24, 2009 1:24 AM
To: Atkins, Seth (RICH1:5278)
Cc: Jurian Sluiman; fw-auth@lists.zend.com; fw-mvc@lists.zend.com
Subject: Re: [fw-mvc] RE: Acl factory the MVC way

Thats ok, but what to do when you need to hide some links on the page? Use view helper?

Regards,
Saša Stamenković


On Fri, Aug 21, 2009 at 7:59 PM, Seth Atkins <satkins@nortel.com> wrote:
There is really one good answer. You need a controller plugin and use the preDispatch method to build and check your ACL. That is if your ACL is going to check module/controller/action access at all. Post routing, the request object has filtered the RequestURI into module/controller/action(s) so you can construct your ACL using this information. And between routing and dispatch leaves pre-dispatch as your only option.
 
The only choice at that point is which pre-dispatch you want to use. You can hitch pre-dispatch code as a method in each controller, but then you would have to duplicate your code a bunch of times for each controller which isn't very maintainable, so the best solution is to use a controller plugin since controller plugins are initialized prior to dispatching to a particular controller meaning your ACL code for creating and checking is in just one location.
 
Sure you could have an ACL controller, but then that means you have to force all requests through that controller prior to being redispatched again later. Plugins are so much simpler.
 
What I did was that I have a very simple plugin. It calls an ACL creation method followed by a simple isAllowed statement that checks the request against the ACL.
 
Where you place the factory code and so forth is really just a matter of personal preference. I didn't want to bloat up my plugin, so I moved the heavy lifting code to another factory class. And I felt that this is a library, which meant I placed it in /library/MyStuff (or something like that). Of course with 1.8+ you have to mess with namespaces to do that, but not a big deal.
 
My ACL factory in turn calls the database to gather info around hierarchical permissions and so forth, so that means the factory instantiates a Model_AAA (I felt it nice to have a simple model for all things authentication/authorization related), which then has a method for querying the database. I placed this model in the default (module) namespace. But put it where you want.
 
Last comment. After lots of wrestling over how to manage hierarchical permissions in a database structure, I settled on a nested set structure rather than a recursive structure. This takes a little getting used to, but it handles nesting of levels of resources so much better than trying to recurse many times. Google around and you should find some help on how to manage queries against a nested set. You can do lots of things such as gather the full parent branch of the tree from any given resource, etc. as well as find every sub tree from a given node. It is very powerful, and you can use this for group/role nesting as well if you have a complex group structure.
 
 
 

--Seth

 


From: Jurian Sluiman [mailto:subscribe@juriansluiman.nl]
Sent: Thursday, August 20, 2009 2:56 AM
To: fw-auth@lists.zend.com; fw-mvc@lists.zend.com
Subject: Acl factory the MVC way

Hi all, [1]


I'm trying to get the Auth+Acl combination working with very dynamic pages where pages are in categories (they can be inherited and act like a domain or something) and users are in groups (inherited as well).


Because of the complexity I'd like to use the factory method of the CodeUtopia post [2]. I'd like to do this completely MVC and the ZF1.8 / ZF1.9 way. This is my set up:


- A front controller plugin, checking each page view for the right Acl permission
- Some models in the default module (Model_Acl_User, Model_Acl_Group etc)
- An Acl stored in the registry for more control later in the process (e.g. permission to edit etc)
- A factory to create the Acl with only the roles and resources necessary


Now the problem: where should I place the factory??? It's not a model, it's not a front controller plugin, an application resource doesn't seem right to me either. A factory class in my own library is an option, but is it the best option? What about an AclController in the default module?


I'd like to hear you opinion about this problem.
Thanks in advance,
Jurian Sluiman


[1]I hope you don't mind, but it's Acl in MVC so I sent it to both lists trying to get the best of both worlds
[2]http://codeutopia.net/blog/2009/02/18/zend_acl-part-3-creating-and-storing-dynamic-acls/
--
Jurian Sluiman
Soflomo.com


没有评论: