JSkimming / AspNet.Identity.EntityFramework.Multitenant

Multi-tenant support for ASP.NET Identity using Entity Framework
Apache License 2.0
132 stars 61 forks source link

How to refer to TenantID value #2

Closed randeep80 closed 10 years ago

randeep80 commented 10 years ago

I downloaded the sample solution and played around with it. I notice that there is TenantID column created in User table. But how can I refer this in my solution? I can't find any reference; e.g. User.Identity.TenantID? Could you advise method of retrieving it in Model, Views or Controllers?

JSkimming commented 10 years ago

Hi @randeep80 the User.Identity property is a Microsoft core interface of type IIdentity, I cannot add a property to that interface. What are you looking to achieve? Was it something like the IdentityExtensions methods? Currently the solution makes no attempt to save the Tenant Id as part of the claim.

The ApplicationUser class derives from MultitenantIdentityUser which has a TenantId property.

Also, the MultitenantUserStore also has a TenantId property, you can see it being set here in the example project.

randeep80 commented 10 years ago

Could you please give me a hand here : How can I call the Mutlitenant class here?

    public static int GetTenantID(this IIdentity identity)
        {
        if (identity == null)
            throw new ArgumentNullException("identity");

        var userStore = new MultitenantUserStore<ApplicationUser>(new ApplicationDbContext());

        string stringTenantID = userStore.TenantId;

        int tenantID;
        if (string.IsNullOrWhiteSpace(stringTenantID) || !int.TryParse(stringTenantID, out tenantID))
        {
            return default(int);
        }

        return tenantID;
    }
randeep80 commented 10 years ago

Also I'm planning to use this with MySQL database. Do you foresee any issue with that?

JSkimming commented 10 years ago

Hi @randeep80 looking at what you're attempting that wont work, MultitenantUserStore has a TenantId property to use it with one of the custom queries, it needs to be set by your implementation.

The IdentityExtensions methods are there to provide simple access to the claim data, have a look at the source. As I said above:

Currently the solution makes no attempt to save the Tenant Id as part of the claim.

Maybe you're going about this the wrong way, presumably your system is multi-tenant in more than just user access, how are you differentiating tenants in other parts of your system?

Regarding using this with MySQL, I don't know how well Entity Framework works on MySql as I've never tried it, it appears Microsoft.AspNet.Identity.EntityFramework works on MySql, at least according to this blog. I'm not doing anything special with Entity Framework in adding the TenantId columns, so it may work just fine.

randeep80 commented 10 years ago

Hi James, I'm using multi tenant on same database tables with a TenantID column in each table to associate the records. And currently we associate tenant id with a user as per your approach. I applied automatic filtering in EF, so that data is always filtered by logged in user TenantID. And certain times I need to manually pass TenantID back to database, for filtering, e.g. to stored procedures. So I need flexibility to access User Tenant ID across Model, Views and Controller. (Am now using HTTP Context to store the value)

Currently a user account can belong to only one tenant. But am trying to change the approach, where a user can belong to multiple tenants (will create a intermediary table for 1:N relationship). So if user belongs to multiple tenants; upon login we will prompt another page to select which tenant user want to access. And will store back this selected tenant in User table as default selection. Hence am able to retrieve back the current TenantID from your Multitenant Identity model.

randeep80 commented 10 years ago

Hi James, Appreciate if you can point me to a sample on how I can save and retrieve Tenant ID using custom implementation.

    public static int TenantID(this IIdentity identity)
    {
        if (identity == null)
            throw new ArgumentNullException("identity");

        ApplicatonUserStore userStore = new ApplicatonUserStore(new ApplicationDbContext());

        return userStore.TenantId;
    }
JSkimming commented 10 years ago

Hi @randeep80 then I think you need to manually add the TenantId as a claim upon sign-in/registration.

I've created a gist as an example. Use the SetTenantId() extension upon successful sign-in, then use GetTenantId() to get the TenantId during authenticated requests.

Beyond that there's plenty of information on ASP.NET Identity and claims.

Hope that helps.

randeep80 commented 10 years ago

Thanks for above James, but I can't really retrieve back the value from GetTenantID functions - it always returns null. Anyway, I will explore more on that.

But I have another serious problem. I defaulted my tenantID as 1. And now if I manually change the value to anything but 1 in AspnetUser table, FindAsync will not return result.

  var user = await UserManager.FindAsync(model.UserName, model.Password);

  public UserManager<ApplicationUser, int> UserManager { get; private set; }

    public AccountController()
        : this(new UserManager<ApplicationUser, int>(new ApplicatonUserStore(new ApplicationDbContext()) { TenantId = 1 }))
    {
    }
JSkimming commented 10 years ago

Hi @randeep80 That's by design, it's frankly why I created this solution in the first place.

Users are unique (by user name) within a Tenant, but not across tenants. For instance, the user randeep80 under tenant 1 is a different user than one with the same user name under tenant 2. Therefore users created under tenant 1 do not exist under tenant 2 unless recreated, and still then they are different users.

Also, if you do have "another serious problem" again, can raise a separate issue?

Unless you object I'm going to close this issue.