views:

532

answers:

2

I would like to build a ‘User’ Object model for a somewhat typical web application…however I cannot decide how best to design the object model & role system.

Basically I plan to have about 4 user types…which will correspond to user ‘roles’ in the membership provider.

These types will be: • Worker • Employer • Guest • Admin

The super type is: • User

In addition – a User could be both a ‘Worker’ & an ‘Employer’ at times.

I would like to use the MS Roles & Membership provider & have navigation UI set to respond to User Role.

My question is: How can I best design these Users to be flexible (User can be Worker & Employer). How do I handle the Login / Roles Procedure?

(I am thinking about a User with a Factory for ‘Behavior’ objects (worker behavior, Employer Behavior ) )

For Login-User logins in … finds its role and Casts to its subtype. Is this how it should be done? thanks

+1  A: 

Using just the concept of role by itself has always proven to be in adequate for me. It doesn't provide low enough granularity to control permissions. AS an example you may have a worker role and and an admin role and then in code you use principal.IsInRole("Admin") to check their role to determine if they can modify some value (say salary). Then someone changes their mind and says that supervisors can change salaries but still aren't admins. Now you have to go change you access check to add in another role check. Painful and routine.

So what I do is make a list of all the features in the application and then allow them to be associated in to a role all in the database. The my access checks look like principal.HasPermission("CHANGESALARY"). I load up the users permissions based on the role they are attached to when they log in. This way the business can create as many groups of features they want and name them. They can then be applied to any user.

I create a custom principal object and attach it to the thread so that I can use it in any code throughout the page life cycle. This object has the code for loading the permissions from the database and the methods for checking permissions.

I generally find that the "providers" in the framework are good for a small class of applications and come up short for most needs. By the time you are done bending them to your will, it would have been easier to just write it from scratch.

DancesWithBamboo
A: 

To be honest, this is probably not a very good solution, but it might help to generate some other ideas.

My Roles are all of the possible combinations of permissions:

Worker, Employee, Guest, Admin, WorkerEmployee, etc

In my code I have an enum for the individual permissions

[Flags]
public enum RolePermissions
{
    Guest = 1,
    Worker = 2,
    Employee = 4,
    Admin = 8
}

and I have an enum that corresponds to the Roles in the database. The integer values are the bitwise OR of permissions:

public enum AvailableRoles
{
    None = 0,
    Guest = RolePermissions.Guest, //1
    Worker = RolePermissions.Worker, // 2
    Employee = RolePermissions.Employee, // 4
    WorkerEmployee = RolePermissions.Worker | RolePermissions.Employee, // 6
    Admin = RolePermissions.Admin, // 8
}

Then there's a set of methods I can use to look up permissions and whatnot:

// Used to determine if the currently logged in user has a particular permission (Guest, Worker, Employee, Admin)
public static bool UserHasPermission( RolePermissions rolePermssion )
{
    foreach( string role in Roles.GetRolesForUser() )
    {
        AvailableRoles availableRole = Parse( role );

        if( ( (RolePermissions)availableRole & rolePermssion ) == rolePermssion )
            return true;
    }

    return false;
}

// Used to determine whether the currently logged in user is in a specific role
public static bool UserIsInRole( AvailableRoles requestedRole )
{
    return UserIsInRole( Membership.GetUser().UserName, requestedRole );
}

// Used to determine whether a specific user is in a specific role
public static bool UserIsInRole( string username, AvailableRoles requestedRole )
{
    foreach( string role in Roles.GetRolesForUser( username ) )
    {
        AvailableRoles actualRole = Parse( role );

        if( actualRole == requestedRole )
            return true;
    }

    return false;
}

// Helper method to parse enum
private static AvailableRoles Parse( string role )
{
    return (AvailableRoles)Enum.Parse( typeof( AvailableRoles ), role );
}

If you come up with a better method or make improvements, please let me know so I can incorporate it back into my own code. :-)

Greg