Question

I am currently trying to create my own authorization system with Symfony (version 2.3). And I am not sure if I am overcomplicating things, I am pretty new to Symfony and SOA. I am creating my own authorization system because I have the need to restrict rights according to current user, its role and a current customer (current user can change customer) and its products.

What I currently have and I think may be too complicated is the following:

Foreach entity I have a repository for read operations only:

MyBundle/Entities/
                  Customer.php/CustomerRepository.php
                  Product.php/ProductRepository.php
                  ...

To abstract the usage of the repositories and also the handling the create/update/delete. I have a Manager class per entity which are using the repositories (proxying to the repositores and usage of combination of different repos).

MyBundle/Manager/
                  CustomerManager.php
                  ProductManager.php
                  ...

Then I have my classes which are are getting the authorization according to current user, its role and a current selected customer and its products. They are using the Managers for loading all the acl data.

MyBundle/Authorization/
                       AuthCustomers.php //Allowed customers to which user is assigned
                       AuthRights.php    //Rights according to user and customer

The services look like this:

auth.manager.product:
    class: MyBundle\Manager\ProductManager
    arguments: ["@doctrine.odm.mongodb.document_manager"]
auth.manager.customer:
    class: MyBundle\Manager\CustomerManager
    arguments: ["@doctrine.odm.mongodb.document_manager"]

auth.authorization.authorization_rights_factory:
    class: MyBundle\Authorization\AuthorizationRightsFactory
    arguments: ["@auth.manager.role", "@auth.manager.customer"]
auth.authorization.authorization_customers_factory:
    class: MyBundle\Authorization\AuthorizationCustomersFactory
    arguments: ["@auth.manager.group", "@auth.manager.customer"]

Until this point I actually think it is ok. But what I would need now and what concerns me is, when doing some action on any of these entities I would actually need to do a check with my AuthorizationXXX services if I am allowed to do it. So the Authorization class is dependant on the Manager and the other way round.
To abstract this (to prevent infinite reference and I can reuse this in a controller and command script) I would now create another service where I inject the Authorization and Manager services and do these checks. So I would actually have another manager for my services.

In the end I would then have 7 entities, with 7 repositories and 7 Managers + a few authorization classes + 7 services to combine the managers and the authorization classes.

The question now is, is this the right way? I really feel like I am overcomplicating things. Any simpler suggestions are welcome :)

Was it helpful?

Solution 2

In the end I now just kept the structure and just changed the meaning of the layers a little bit. What I now have and feel comfortable with is:

Repositories for read only operations, are aware of other repositories (here I overdid it it in the beginning by wanting to keep the repos unaware of each other).

Manager which are handling persistence of the entities and proxying through to the read operations from the Repositories. They don't care about Authorization.

Authorization services which just handles my authorization things, so they can be reused anywhere without having to do Symfony specific stuff.

Model service which combines the Manager and Authorization and generally all depencies. Actually the Symfony controllers would just call the model services' methods. But with this I can also reuse it for Command line scripts etc.

I still have a lot of classes, but they are now nicely separated and only do their stuff and could be replaced easily.

In general I also looked at the FOSUserBundle in detail to get some inspiration. I think they solved it pretty well in general.

OTHER TIPS

Voters seems to fit with your need, check out the doc: http://symfony.com/doc/current/components/security/authorization.html#voters

You could create a Voter which take as argument the current user, his roles and the current customer and return true if your business rules are respected and false if not.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top