1

I have 3 different types of users (with different roles) interacting on my web application, they all perform some task - some can be exactly the same e.g. create a quote others can be unique to that specific user e.g. sign off quote.

For more clarity 3 types of users: Client, Supplier, Customer.

Client or Customer can create a quote, however only the Customer can sign off a quote.

How do I ensure my application allows clients to access client speficic controllers and suppliers to access supplier specific controllers or areas. Via Custom Attributes? Do I store the type of user inside a cookie? Is this safe? or Session state? As soon as someone logs onto the system I send back a LoggedOnDTO object on which I store Username, UserID, and type of user....

NOTE: I went away from asp.net build in way of creating users, I have my own custom tables with my custom mechanism for logging into the system. I have a registered Model Bindiner that looks for the prefix and I send in a strongly typed object to each action...

Sample code:

[HttpGet]
public ActionResult AddComment(int quoteid, ClientUserDTO loggedonclientuser)
{

}

[HttpGet]
public ActionResult AddCommentSupplier(int quoteid, Supplier loggedonsuppluser)
{

}

EDIT: This method for some reason seems so much simpler... Is there something wrong with it? Any possible security issues? Threading?

My session controller is:

if (_authService.isValidUser(model))
{
   var data = _authService.GetAuthenticationCookieDetails(model);
   AuthenticateCookie.AddDetailsToCookie(data);
   return Redirect(Url.Action("Index", "Activity"));
}

When I create my cookie... I can simple store "ClientUser", "Supplier" or whatever role they are inside the cookie.

Then I can create an Attribute and read in the cookie data to see if they are a valid user e.g.

public class ClientAuthorizationAttribute : AuthorizeAttribute
    {
        public bool AlwaysAllowLocalRequests = false;
        protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
        {
            if (AlwaysAllowLocalRequests && httpContext.Request.IsLocal)
            {
                bool authorized = false;
                var result = UserDetails.GetTypeFromTicket(httpContext.User.Identity as FormsIdentity);

                if (result.Equals("client", StringComparison.OrdinalIgnoreCase))
                {
                    authorized = true;
                }
                //throw no access exception?
                return authorized;
            }
            return base.AuthorizeCore(httpContext);
        }
    }

Register the attribute under my base controller and I have a simple working solution???

Haroon
  • 3,402
  • 6
  • 43
  • 74

2 Answers2

4

Write a custom MembershipProvider and a Custom RoleProvider then you can decorate your controler class or specific methods with the attribute

<Authorize(Roles:="ROLENAME")>

You can learn how to make that your asp mvc use the custom membershiprovider in this question It's really easy.

Edited: The way you did it looks right, but I think you take the long way. Implementing your own MembershipProvider and your own Roleprovider will take you no more than 20 minutes... and you will have the benefits of being working with a well tested and documented system and still having the benefits of use your own database tables for the login. In a simple login system, you only have to write two functions in the roleprovider (GetRolesForUser and IsUserInRole) and only one function in the membershipprovider (ValidateUser) and you will get your system working.

If you want, I can put somewhere (maybe pastebin) a well commented versión of a membershipProvider as well of a roleprovider that i'm using in a simple app (they're made in vb.net but i'm sure it will not be a problem)

Community
  • 1
  • 1
Jonathan
  • 11,809
  • 5
  • 57
  • 91
  • +1 yep this is the best way, and very easy once you see some code. – Russ Clarke May 31 '11 at 15:23
  • Thanks... I am going to have a look into this on Monday and will accept your answer then if it is ok... – Haroon Jun 02 '11 at 11:23
  • If you need something about this topic, just let me know. – Jonathan Jun 03 '11 at 08:06
  • @Jonathan, I have updated my code to show how I would have done this, care to comment? – Haroon Jun 06 '11 at 15:16
  • @Jonathan- yeah that would be great, please do provide a link... I think I will mark your answer as correct after I see a proper example. The problem I am having is- my solution feels more simple to me, It fulfills the same purpose, yes it is not so elegant or extensible... Regardless- I am using Ninject, I have to hook my provider with the domain service layer, If I could see some code, then maybe I could figure out the rest :p – Haroon Jun 10 '11 at 09:19
  • @Jonathan- Just to reiterate... I have a ValueProvider which talks to the database and gets returns a strongly typed object into the controller... would your method involve calling the database again? That does not sound right to me... thanks. – Haroon Jun 10 '11 at 09:59
1

You can also write generic code in the base controller instead of decorating each action with Authorize attribute. Please refer below url.

Good practice to do common authorization in a custom controller factory? custom-controller-factory/5361846#5361846

Community
  • 1
  • 1
vrluckyin
  • 1,026
  • 8
  • 15
  • I like your code, however I feel it is better to use an authorize attribute... #1 it is threadsafe, I am inheriting from a class (AuthorizeAttribute) that just simply works, if user is not valid the attribute itself will kick the user out of the system... – Haroon Jun 10 '11 at 09:21