Which tier of my ASP.NET MVC application should I be checking Membership information?
Asked Answered
S

1

8

I have an MVC application which has the (simplified) structure as below (left-to-right)

UI -> CONTROLLERS -> SERVICES -> REPOSITORIES -> DATABASE

We've attempted to keep each layer decoupled from the next. We're using .NET Membership to manage security, and we have a permissions based function, let's say "Show me all documents for my user type".

Should:

  1. The Services layer have no awareness of our .NET Membership provider? We'd then have Service layer methods which looked like "GetDocumentsByUserType(int UserTypeId){ .. }"?

  2. The GetDocumentsByUserType() method be aware that we're using .NET Membership, use Membership methods to get the current user type, and return the relevant documents?

Also:

  • Does #1 make my Services layer less secure, as my controller layer
    could pass in anything it wanted as a UserType?
  • Does #2 make my Services layer too dependent on a specific technology, namely .NET
    Membership? Is there another way to consider here?

Hope I've provided enough details. Please shout if not and I'll add.

Thanks.

Sisyphean answered 6/10, 2011 at 11:17 Comment(0)
F
7

You should keep all membership stuff inside the presentation (controller) layer. Suppose you ever want to add another presentation layer (or make changes to your existing layer), you'll have a hard time fixing this. Besides, you are duplicating code between your presentation layer and your services layer, which is never a good idea.

Having said this, there is no reason not to perform security checks inside your services layer but you can do this without needing to use the membership classes. First of all, the currently authenticated user is available from Thread.CurrentPrincipal (inside your service layer methods). You can use this IPrincipal to perform security checks.

Second, you can use the PrincipalPermissionAttribute to enforce security rules on your service layer methods or classes. For example:

[PrincipalPermission(SecurityAction.Demand, Role="Administrator")]
public void MySecureServiceLayerMethod()
{
    var p = Thread.CurrentPrincipal;
    ....
}

For the role stuff to work, you'd also have to use a RoleProvider implementation.

UPDATE: As Wyatt Barnett explains in a comment, using PrincipalPermission has some disadvantages. First of all, testing your code becomes more difficult. Another (larger) disadvantage is that you hard-code role names into your code. These names are usually not owned by the developer.

Farly answered 6/10, 2011 at 11:35 Comment(2)
+1, IPrincipal is the way to go. Especially custom IPrincipals. PrincipalPermission is really nifty, but having used it on a project heavily I'd really argue against using it -- it is a bit of a landmine for folks and really makes testing difficult while also being difficult to test.Lues
Here is where it gets interesting, what if I need the primary key field that represents the user in the database? I know I could get the name field for the user but I would rather use the primary key field. How could I access this from the IPrincipal without setting the name field to the primary key value(I know that suonds bad).Glib

© 2022 - 2024 — McMap. All rights reserved.