0

To support tenan/companies, I added/extended a new property to the AspUser Table called OrgId in ASP MVC 5, Identity 2.2 role management, I added the corresponding OrgId to some other tables, looked here but no answers

During User Login() and the UserSession

  1. how do I cache, configure & retrieve the OrgId, so that I can perform DBConext filtering/CRUD of table for Org specific records?
  2. Advice: is better to save this in the Claims, FormsToken or Session - and how to set the tenanId context in session?

I know how to get user, but not the extended Org

ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());
Community
  • 1
  • 1
Transformer
  • 6,963
  • 2
  • 26
  • 52
  • Is your ApplicationDbContext class derived from IdentityDbContext ??? – Efe Feb 25 '17 at 20:47
  • @Efe yes I belive so. Do I have to query the DB, or does it go around with the Identity Object since I add that property – Transformer Feb 28 '17 at 06:27
  • U can easily query db if you inherit correctly. I've done this before. Just give me 30 mins to post whatever i've done for you. Im on my way to office – Efe Feb 28 '17 at 06:56

2 Answers2

1

Your customized user class should be like this:

public class CustomizedUser : IdentityUser
    {
        public int OrgId {get; set;}
        public DateTime JoinDate { get; set; }
        //...
        // and other simple fields

       //Fields related to other tables
        public virtual ICollection<Article> Articles { get; set; } = new List<Article>();
      //...      
}

And your CustomizedApplicationDbContext class

public class CustomizedApplicationDbContext : IdentityDbContext<CustomizedUser>, IApplicationDbContext
{
    public CustomizedApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static CustomizedApplicationDbContext Create()
    {
        return new CustomizedApplicationDbContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //your entity configurations go here if you have any

        base.OnModelCreating(modelBuilder);
    }

    //These fields are neccessary in order to maintain the power of base class
    public DbChangeTracker Changetracker => base.ChangeTracker;
    public Database DatabBase => base.Database;

    //your own dbsets go here except CustomizedUser, because the base class IdentityDbContext<CustomizedUser> handles it
    public IDbSet<Article> Articles { get; set; }
    //...

}

Now, Remember to replace every ApplicationDbContext references with CustomizedApplicationDbContext and every IdentityUser refrences with CustomizedUser in your code (specially in your ManageController created by mvc).

From now on, you can easily access users table just like other tables:

var db = new CustomizedApplicationDbContext();
var user = db.CustomizedUsers.First(x=> x.OrgId == 10 || Email == "sth@yahoo.com");

And to get the current user OrgId, you can use something like this(without querying db):

var currentUserOrgId = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(User.Identity.GetUserId()).OrgId;

Hope this was helpful

Efe
  • 800
  • 10
  • 32
  • hi @Efe , can you tell me how to handle this scenraio if I have EF Database First, where do I put the new values like Company, or MedicalPlan. Or can you also recommend if I should not use DB first and change, or what to do... I am stuck in this loop – Transformer Feb 28 '17 at 19:46
  • @transformer Hi. Actually, it depends on what you are comfortable with. I haven't used db first for a scenario containing Identiy, but the 2nd and 3rd answers in this link might help you. http://stackoverflow.com/questions/19940014/asp-net-identity-with-ef-database-first-mvc5 .Now,if you ask my recom, I personally dont like visual tools like edmx, because I barely understand what's going on behind the scene. Besides, asp mvc is a separation of concerns and instead of creating tables with sql query or models with edmx, I try to focus on concept of mvc and write a better reusable code. – Efe Feb 28 '17 at 22:35
  • I personally prefer codefirst, because it gives me full control over my domain and it is really easy for me to implement even more complex scenarios. It is pretty simple and managable. If your project's progress is below 50%, I recommend you to switch to codefirst. Again, it's up to you. There are lots of articles about pros and cons of ef codefirst on the internet, please check them before making or changing your decision, but I bet you will choose codefirst if you are looking for flexiblity. – Efe Feb 28 '17 at 22:36
  • You can use claims for your scenario but do not mess up claims if you dont use OrdId for authorization purposes. And finally, about the link in your question, his problem can be solved by defining access levels(a new entity) for roles. Access level should be in many2many relationship with roles.Therefore, we can define access level for each action in our controllers(using attributes) and let user dynamically set access levels(access to actions) to roles. Using the method I suggested, roles can be defined dynamically and applied dynamically to actions. – Efe Feb 28 '17 at 23:03
  • thanks for the response, I marked it as answer, its right at 50% - what are the steps to switch to code first? – Transformer Mar 01 '17 at 00:12
  • @transformer There are lots of articles about migration from db first to code first like this simple one: https://www.codeproject.com/Articles/1078074/Migrating-a-Project-from-Database-First-to-Code-Fi . The best approach is to seperate your domain models to a new class library project. You will also need to use DataAnnotations or Fluent Api(my favorite) for your relationships. Once you start with a simple test project with two entityes, it will be a charm for u. Most tutorials do not have Identity customizing examples, but u can use the answer to make your job done. Hope these where helpful – Efe Mar 01 '17 at 07:12
1

You can get the current user in ASP.NET Identity as shown below:

ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext()
    .GetUserManager<ApplicationUserManager>()
    .FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());

//If you use int instead of string for primary key, use this:
ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext()
    .GetUserManager<ApplicationUserManager>()
    .FindById(Convert.ToInt32(System.Web.HttpContext.Current.User.Identity.GetUserId()));


For getting custom properties from AspNetUsers table:

ApplicationUser user = UserManager.FindByName(userName);
string name = user.Name;

Hope this helps...

Murat Yıldız
  • 11,299
  • 6
  • 63
  • 63
  • Hi, I am doing this and going to the database everytime to get the information, like my question 1) is there a way to cache that information? or is it better to add it in claims 2) below efe also gave some nice suggestion, but my case is database first and who can I easily do this with DB first. – Transformer Feb 28 '17 at 19:48
  • 1) You are right, but I am not sure which one is better. But generally the given approach seems to be used as I first searched this issue. On the other hand you might have a look at [Efficient caching of Identity related entities](http://stackoverflow.com/questions/22166063/efficient-caching-of-identity-related-entities) and [Get ASP.NET Identity Current User In View](http://stackoverflow.com/questions/27139068/get-asp-net-identity-current-user-in-view) threads. 2) I have already used many times the given approach in DB First without any problem. – Murat Yıldız Mar 01 '17 at 07:07