2

This is a pretty general question, actually..

I have a user class (doesn't every app ? :). Certain users can perform actions on different entities, given they have proper permissions. What is a better place to put the authorization logic (or any logic that works with 2 instances) ?

If I put it in a User class, I end up with a bunch of user.CanEditComment(), user.CanEditMessage(), user.CanDoSomething() etc methods - could be a few methods for each entity that requires authorization. Seems like method clutter.

On another hand, I can put these methods in entities, like comment.CanBeEditedBy(user). But somehow it doesn't seem quite right either...

Any suggestions ?

Thanks !

Alex Kovanev
  • 1,858
  • 1
  • 16
  • 29
Evgeni
  • 3,341
  • 7
  • 37
  • 64

3 Answers3

3

Another option would be to mimic what the ASP.NET roles do and define a collection of roles and assign them to users. Then, your features can query the user for the role(s) needed to access the feature. Your user class only needs one method HasRole(string roleName), and your features control their own access.

drdwilcox
  • 3,833
  • 17
  • 19
  • It's not just the role, though. Say you post a comment on a forum, now you're the only one who can edit it (besides forum admin.. not relevant in this case), even though you're not in an admin role. You're the comment creator, though, and it's a pretty trivial check, but I want to put this check in a method (DRY), hence the question. – Evgeni Dec 21 '11 at 01:50
2

I think the best place for putting data for the authorization logic is your database. Depending on your requirements you can create some tables like Users, Roles, Permissions, Locations etc. Recently I did ask a question. You can take a look at the scheme.
The next step is authorization logic. The first thing that occurs to me is using a custom attribute class with the overrided OnAuthorization method.

public class PermissionsAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        // the best place for your authorization logic
    }
}

It will give you a possibility to separate access inside controllers in a very convenient way (as for me).

[Permissions()]
public ActionResult Some()
{
}  
Community
  • 1
  • 1
Alex Kovanev
  • 1,858
  • 1
  • 16
  • 29
  • I have all needed data in DB, and it's pretty trivial to check for permission, but I end up with a longish LINQ statement, which I want to encapsulate in a method... which I need to put somewhere. I also can't work with attributes, because I need to check current user's permissions to a specific item (not a permission to execute some action for all objects of given type). – Evgeni Dec 21 '11 at 02:11
  • Ok. For encapsulating nobody forbids you to create a class where you'll put your linq inside some method. Evidently I don't understand why you can't work with attributes. MVC pattern implies every significant client's action passes through controllers. Where is the problem here? – Alex Kovanev Dec 21 '11 at 02:22
  • Actually no, my bad, yes I can authorize via attributes. However, this will lead to duplicate DB access - first to get an item to check the permissions, then get it again in a method to actually display it. I'm using ORM, so the control over the sql is somewhat limited. I also have a feeling that this should be done in model - but I might very well be wrong here. – Evgeni Dec 21 '11 at 02:35
  • IMO this will be secure. Let's imagine you have a user with no possibility to edit some page. Of course you can check him before and just not to show a link for editing. But who will prevent him to try getting access to that action? – Alex Kovanev Dec 21 '11 at 02:42
  • I will run that check in a controller. Basically, i'm looking at either the attribute, like in example above, or running authorization in a controller itself (e.g. user.CanEditSomething(id), or something.IsEditableBy(user) ). I'm leaning towards the last option, but some gut feeling tells me there's a cleaner way :). – Evgeni Dec 21 '11 at 02:56
1

See my answer to this question. Because you store everything in DB, you can change the enum Role to a string list(which is load from DB).

Community
  • 1
  • 1
Cheng Chen
  • 42,509
  • 16
  • 113
  • 174