Question

I have a multi-tenant app that's using SimpleMembership. Each User in my system is linked to one or more Tenants. I've extended Users simply by adding the required fields to the User model (and Tenants):

public class User{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public virtual ICollection<Tenant> Tenants { get; set; }
}

This is working great. But now I'd like to have Roles be tenant-specific, where some role types MUST have a TenantId defined. This isn't as simple as the user problem, as each of the following will be affected:

Adding Roles, Checking Roles:

 if (!Roles.Privider.RoleExists("Moderator"))  // I now want to include TenantId here
        {
            roles.CreateRole("Moderator"); // and here
        }

Assigning/Checking Roles Using Provider:

    if (!Roles.IsUserInRole("Admin", "SystemAdministrator")) // and here
        {
            roles.AddUsersToRoles(new[] { "Admin" }, new[] { "SystemAdministrator" }); // and here
        }

Role Attributes:

 [System.Web.Http.Authorize(Roles = "SystemAdministrator")]
 public class AdminApiController : BaseApiController 

User.IsInRole:

 if (User.IsInRole("Administrator"))
            {

I'm pretty new to ASP.NET, so I'm not sure where to begin here. Should I be overriding the SimpleMembership Role Provider somehow, or should I look into writing my own Role columns, classes, etc? It would feel wrong to hand-code anything around authentication... Any pointers around this would be much appreciated.

Was it helpful?

Solution

The first problem I see with implementing this is the use of the AuthorizeAttribute because attributes require constant information defined at compile time. With your tenant-based approach I would think which tenant to check would need to be determined during run-time. So the first thing I would do is take the approach described in this article on Decoupling You Security Model From The Application Model With SimpleMembership. Now you decorate this attribute with a resource and operation (which will be static) and you can configure what roles are assigned to the resource/operation at run-time in the database. This gives you a lot more flexibility in designing your security model as you add tenants.

Changing the database model for anything but the UserProfile table in SimpleMembership is not possible (See this QA). So adding tenant ID's to roles is not possible without writing your own membership provider. If you want to stick with using SimpleMembership one solution is to handle this in your naming convention for roles, where you include the role name and tenant name or ID. For example, if you have two tenants that have the admin role you would have two roles that are named "Administrator_Tenant1" and "Administrator_Tenant2". If you need to display this to any users that assign roles you could clean up the name by stripping out the tenant ID/Name for viewing.

If this is a new project and you are not tied to SimpleMembership you may want to look at using at Microsoft's latest membership system called ASP.NET Identity. This membership system replaces SimpleMembership in MVC 5. ASP.NET Identity was built to be easily customized and you should be able to change the role model. There is an article on customizing ASP.NET Identity here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top