views:

72

answers:

3

I am trying to design an application in 3 layers :

1) Data access layer
2) business layer
3) UI

I try to keep classes decoupled so on the business layer I have created interfaces for the Data access classes like this :

public interface ICountryRepository:IRepository 
{
    Country  GetCountry(int ID);

    int CreateCountry(Country obj);
    Boolean UpdateCountry(Country obj);
    Boolean DeleteCountry(Country obj);
    ...
    ...
 }

and i pass the interface as param to the service constructor :

   public CountryService(ICountryRepository repository,ILanguageRepository lang_repository)
   {       
    ....
   }

But on the CountryService for example I need to load the current user and his permissions so I can check if the operation can be applied :

    public Country GetCountry(int ID)
    {

        if securityService.UserHasPermission(currentUser, GetPermission("CanGetCountry"))
        {
           return repository.GetCountry(ID);
        }
        else
        { 
           Throw(New SecurityException("No permissions for that operation ...."))
        }

    }

That means I have to instantiate the SecurityDataAccess object and pass it to the constructor of the SecurityService on my business layer assembly which I try to avoid for keeping objects decoupled. Right now I even don't have a reference to any DataAccess assembly on my business assembly.

I am thinking of using an IoC container here. Using external configuration I could get the right class/assembly from a config file. But I am not sure that is the right solution because it is said that IoC containers should be used in one place to keep things simple and it should be the top level assembly (the UI assembly) most of the time.

Anybody has a suggestion for solving this problem ?

+1  A: 

Why not add the security service into the constructor of the Country service? That way the IOC Container could resolve the dependency and inject the security if it is needed. That mean the IOC Container would take care of constructing your CountryService object. And you would use the container to get all Services.

Another option could be to "normalize" your repository a bit...

Trim it down to it only has 4-5 basic functions that are identical for all repositories, then use generics to make them all look alike, so no

UpdateCountry(...) but Update(T object)

Something like this: http://codebetter.com/blogs/gregyoung/archive/2009/01/16/ddd-the-generic-repository.aspx

Then you can use a Chain of reponsibilty pattern to place your security code before the DB Code ( http://en.wikipedia.org/wiki/Chain-of-responsibility%5Fpattern )

So you could have a SecurityChecker that validates access, throws an exception if invalid, or passes down the request in the next link in the chain (You can also add a logging dynamically that way, or timing or whatever)

Heiko Hatzfeld
The first suggestion will work. But I try to find a way to avoid passing the security service to every other service. I mention that the DAL classes are plain (no logic at all .. just reads and writes) so no need security there.
George Statis
The security checker will have an iRepository interface, when you construct you repository you pass a refference to the dataservice to the security service. If the user wants to save, then he "just" calls save on the outer security service. It checks if the user is allowed to save,and if thats the case, he passes the call onto the inner data access repository. If the user is not allowed to save, then he just throws an exception, and prevents the save.Take a look at IOC Container, they will help you to construct such chains via configuration
Heiko Hatzfeld
I agree - allowing the iRepository interface on the constructor will give you the flexibility you need. Unless there is another intermediary layer - BusinessObject.SecurityData - that the DAL and BL use, the best you can get is using the iRepository.The iRepository also is straight forward in that you would won't have to go digging through different layers of different assemblies to track down an issues.
David Robbins
A: 

Do you need to implement security in the Data Access layer? If you move your security service to the business layer as Heiko suggests. In other words, perform security in the business layer and you avoid the IoC issue altogether.

David Robbins
In fact I don't want security in the data layer. I want security in the business layer. The problem for me is that I need instantiate the security service so I can read the permissions of current user. But for doing that I have to pass the security DAL to its constructor. That will couple the security DAL with the security service. Thats my problem.
George Statis
A: 

This may be off-beam, apologies if it is, I'm a lurking JEE programmer. It seems to me that authorisation is of methods is better addressed in the infrastructure, declaratively.

This article appears to suggest that .Net, like JEE offers a facility to control access declaratively. Does this approach work for you?

djna