views:

496

answers:

8

Lets say I have an ASP.Net MVC App and this app (UI) references a Business Logic Layer (BLL) and the BLL references my Data Access Layer (DAL).

I am utilizing a Custom Membership and Role provider for Authorization.

I am trying to determine what layers need to reference my Membership provider.

In MVC you can perform Authorization checks in the following manner:

[Authorize(Roles = "SomeRoleName")]
public ActionResult Index()
{
//do something
}

And in my BLL I may want to check to see if a User is in a Role as well:

public static bool IsRoleEditor(User user, Role userRole)
  {
   bool retValue = false;

   if (user.Application.AppID == UserRole.Application.AppID)
   {
        if (Roles.IsUserInRole("ModifyRoles"))
        {
           retValue = true;
        }


    return retValue;
   }

I would have to reference and instantiate the Membership classes in both layers if I do this. Is this the correct way to architect an app like this? Seems like a lot of redundancy.

Since I have a BLL do I avoid using the "[Authorize(Roles = "SomeRoleName")]" attributes and instead call a BLL function from within the MVC code to check if the user is in a role? If I do this the MVC still needs a reference to the membership provider for authentication and such anyway to take advantage of the Login and other ASP controls, right?

Am I way off base and heading in the wrong direction?

A: 

Get your User object to implement the IPrincipal interface and throw that around the layers. Then you can still use the built in [Autorize] attribute.

Athough written over 3 years ago and about castle, this article may help. It starts getting into the IPrincipal stuff half way down.

HTHS
Charles

Charlino
Definitely use the Authorize attribute in MVC. You don't need to manually check IsInRoles.
Anthony Gatlin
The problem is that I do need to process additional business logic in addition to "IsInRole" or "Authorize" which I thought should always be in the BLL.I'm could pass the user object everywhere, but then why not just leave out the Authorize and use only the BLL.
Jay
+1  A: 

Excellent question, I asked myself the same thing today. One of the idea I had (but I'm not really sure if it's the best way to go) is to use a interface (ex: IRoleProvider) that you can pass to your BLL to test your access.

public static bool IsRoleEditor(User user, IRoleProvider rp)
{
     return (rp.IsUserInRole(user,"ModifyRoles"));
}

With this, you still verify your access in your BLL, you can use a mock in your unit tests to check your logic and you just need to create a class (or implement this in a baseController class) in your MVC web site that will implement IRoleProvider and do the proper check using ASP.NET authorization API.

Hope this will help.

mberube.Net
A: 

Role access normally shouldn't be in the BLL. Access is a user interface responsibility.

With that said, leverage the IPrinciple interface as the above posters have stated. You have access to IPrinciple at the Thread level.

Thread.CurrentPrincipal
Chuck Conway
Charles, thx for the reply. As you can see though I have to process some business logic, other than the basic role check, in order to determine in order to determine the users true security. I figured that all BL should be in the BLL which is why I was planning on encapsulating the security there as well. Are you saying that it is preferable that the "IsRoleEditor" above reside in my UI layer and not in a BLL?
Jay
-1 I disagree: authorization (whether role acccess or some other mechanism) is very definitely a BLL responsibility. The UI tier may be running on the client (e.g. Winforms) so can be compromised.
Joe
It really all depends on how you are designing this application. Give us a example of you solution, something simple just project names and how they reference each other.
dmportella
@Joe I disagree with you. Putting authorization into the BLL pidgon holes you into using that implementation of authorization across the entire application and it's views. An assumption is being made that Web Services, Win Forms, Web Forms, REST API, etc... all must have the same authorization. This idea is rife with problems. Consider using AD (Active Directory). AD works great with WinForms, but does not work well with anything web. If authorization must be used in the BLL, I would surround it in an abstraction, probably the provider pattern.
Chuck Conway
Charles makes sense here. You can't expect the BLL to magically do everything. The application is all of these components and each component has its own security requirements. Including the UI, the 'BLL', the database, the server, and any web services you call.
misteraidan
A: 

Why not pass the roles into your BLL so that you do not have any dependency on Membership. Or use an interface like MartinB suggested.

What happens in the future when your stake holder(s) decide to go with a different form of authentication and you no longer work with a Role object?

Example:

IsRoleEditor(User user, string[] roles)
{
  return roles.Contains("ModifyRoles");
}
DennyDotNet
+1  A: 

In my view this is a weakness of the Membership/Role design.

The way I would get round this, for example to have role-based authorization on both UI and BLL tiers in a distributed n-tier app, would be to expose a service in the BLL tier that exposes the relevant bits (GetRolesForUser etc) and is implemented by calling the RoleProvider on the server.

Then implement a custom RoleProvider on the client that is implemented by calling the service exposed by the BLL.

In this way the UI tier and BLL tier both share the same RoleProvider. The UI tier can use knowledge of the current user's roles to improve the UI (e.g. hiding/disabling UI controls corresponding to unauthorized features), and the BLL can ensure that users can not execute business logic for which they are not authorized.

Joe
A: 

Are you not missing the point of MVC. MVC splits out naturaly into tiers. Model (DAL), controller (BLL), View (Presentation). These can go in different projects if you like but as the controller has all the business logic - you only need to access the RoleProvider there.

Then apply patterns such as the repository, pattern etc to split out further if you want.

Davy

Davy
I understand the concept of MVC but then if I set up the BLL to contain the Role validation then why the "[Authorize(Roles = "SomeRoleName")]" capability from within the UI?
Jay
@jay the Authorize attribute is used in the controller, as per Davy said that would be the Business Layer. I think what he is driving at is that you seem to be ignoring the fact that the "layers" have already been split by the MVC pattern. I think it all depends how youa re structuring this solution Jay, could you do a diagram to show us how you are designing this?
dmportella
A diagram would help. Do you mean UI capabulity as in the view? If you do, I think it's nice to just have dumb HTML but you ay have a view where you want to show something based on roles like an 'authorized checkbox' that only supervisors can see in an otherwise shared view. So being able to access roles here is useful in my opinion.
Davy
A: 

To call the MVC controller 'UI' is way off the mark.. The 'C' in MVC is part of your BLL, even if it references classes that you would call the BLL. However, that is not the point of your question.

I think I would solve this problem by asking the question, "is there a real requirement for 100% separation of your 'UI' app and your 'BLL'?". If both components share a dependency on the member/role providers, then let it be so and get to work.

In the case where you unplug your BLL and plug in a new one, perhaps having a shared dependency on a .NET provider is something you can live with. You know that is probably ok and your app just might not fall apart.

I think Joe's answer above makes much sense though...

misteraidan
Not sure the controller is part of your BLL, infact, I think it should not contain any business logic, just orchestration between your domain objects.
David Kiff
WTF is business logic anyway? The whole app is business logic, made up of various components of business logic.. the UI part of the logic, the MVC part of the logic.. having your code properly architected and abstracted is the aim, not applying generic names for complex components. The idea of these straight up and down linear layers is stupid. A solution diagram is a complex map of objects, and dealing with cross over is our job- Jay's problem is a good one, dealing with cross over in dependencies will be a fun task .. I still think Joe's answer made the most sense and now I'm just ranting.
misteraidan
A: 

I think what you are doing is fine.

The authorisation and authentication should live within a services layer, that is perhaps passed into your controllers.

If the controller sets the Principal and Identity and you then use that in the controller through the use of the MVC attributes then it sounds like a good idea.

It would be nice to hide your MVC Membership provider behind an interface, that way you can swap it out for a WinForms Membership provider (for example) and would be able to unit test your controllers.

David Kiff