Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

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

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");
}

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

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...

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.

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top