Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct use of Microsoft.AspNet.Identity 2.0

I'm lost using the authentication method that comes with MVC 5 Template.

I had the need to include the CreateBy user in an entity called client, so after some research I came to this:

Model:

[Table("Clients")]
public partial class Client
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public virtual int UserCreated_Id { get; set; }

    [ForeignKey("UserCreated_Id")]
    public virtual ApplicationUser UserCreated { get; set; }
}

Controller Method:

client.UserCreated_Id = User.Identity.GetUserId<int>();

But I had to change almost everything in the Identity Model:

From

public class ApplicationUser : IdentityUser

To

public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>

And almost 30 changes because of this.

But now I have 2 DbContext:

Identity Context:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public ApplicationDbContext() : base("IPDB") {}

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

My Application Context:

public class MyDbContext : DbContext
{
    public MyDbContext() : base("IPDB")
    {

        // Tells Entity Framework that we will handle the creation of the database manually for all the projects in the solution
        Database.SetInitializer<MyDbContext>(null);
    }

    public DbSet<Client> Clients { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // ANOTHER CHANGE I HAD TO MADE TO BE ABLE TO SCAFFOLDING
        modelBuilder.Entity<ApplicationUserLogin>().HasKey<int>(l => l.UserId);
        modelBuilder.Entity<ApplicationRole>().HasKey<int>(r => r.Id);
        modelBuilder.Entity<ApplicationUserRole>().HasKey(r => new { r.RoleId, r.UserId });
    }
}

My problem now are:

  • Do I need 2 DbContext?
  • Am I associating the user to the client entity correctly?
  • I need to create a list of all users, and aditional information, will I read the information from 2 DbContext?

Please, I need some clear guide because I am very confused right now and I really love to build great code, and I think it's not the case.

like image 330
Patrick Avatar asked Dec 04 '15 23:12

Patrick


People also ask

What is ASP.NET Core identity used for?

ASP.NET Core Identity: Is an API that supports user interface (UI) login functionality. Manages users, passwords, profile data, roles, claims, tokens, email confirmation, and more.

What is Microsoft ASP.NET identity?

ASP.NET Identity is Microsoft's user management library for ASP.NET. It includes functionality such as password hashing, password validation, user storage, and claims management. It usually also comes with some basic authentication, bringing its own cookies and multi-factor authentication to the party.


2 Answers

Type of Id on ApplicationUser

ASP.NET Identity 2.0 is very flexible, while also offering some descent default implementations that will do in mose cases. The MVC 5 template uses the default implementations in most places, but in some cases some extra stuff is added to make customization easier.

Internally ASP.NET Identity always uses IdentityUser<...>. All those template arguments provide a way to chose your own key type, which means you'll have to chose your own IdentityUserRole type as well (as it contains the key).

There's also the convenience default implementation that uses a string for key. The value of the string is the string representation of a GUID.

public class IdentityUser : 
  IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUser, IUser<string>
{
  /// <summary>
  /// Constructor which creates a new Guid for the Id
  /// </summary>
  public IdentityUser()
  {
    this.Id = Guid.NewGuid().ToString();
  }

Having a string as primary key in a database is not that common, but for security sensitive stuff it makes sense. There is no risk that data copied between databases will have colliding IDs, giving users wrong priveleges.

In your case you need to chose: Use the default implementation with a string PK or change the id to an int. In the latter case you have to change "almost everything" in the identitymodel as you've discovered. Although I think you could do without implementing your own ApplicationRole. It should be possible to just declare ApplicationUser as

public class ApplicationUser: IdentityUser<int, IdentityUserLogin<int>, IdentityUserRole<int>....>

DbContexts

In most cases a single DbContext is fine for an application. If multiple DbContexts are used, they should be for distinct different sets of data that do not relate to each other. As you've set up your Client class to relate to ApplicationUser they should both be in the same DbContext. The template tries to convey the thought that the main DbContext of the application context should inherit IdentityDbContext<> by naming it ApplicationDbContext. Use that one, and extend it with your own stuff. I usually rename it and move it to somewhere else, but still I have one DbContext only and let it inherit IdentityDbContext<>.

Rolling your own Identity Solution

Unless you really, really know what you're doing - don't roll your own identity solution. Use an existing one that has been security hardened by external reviews. If you're not happy with ASP.NET Identity you can have a look at Brock Allen's Identity reboot.

For credibility (yes I'm a bounty hunter today): The official ASP.NET documentation links to my blog.

like image 116
Anders Abel Avatar answered Sep 28 '22 18:09

Anders Abel


Do I need 2 DbContext?

Having a DbContext for the Identity and other for the rest of the app is considered a good practice for some people. However it is not mandatory, and I don't think it is necessary.

You should not have big dbcontexts, smaller contexts are faster. It means that sometimes you have to create more than one dbcontext. I believe 50 entities per context should be enough.

Am I associating the user to the client entity correctly?

You are not (in my opinion). The ApplicationUser uses a Guid (by default) to represent its primary key value, not an Int32. So, instead of this:

public virtual int UserCreated_Id { get; set; }

[ForeignKey("UserCreated_Id")]
public virtual ApplicationUser UserCreated { get; set; } 

you should use this (remember to remove the virtual in UserCreated_Id):

public Guid UserCreated_Id { get; set; }

[ForeignKey("UserCreated_Id")]
public virtual ApplicationUser UserCreated { get; set; } 

in your context, this should be enough:

public class ApplicationUser : IdentityUser
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>

I need to create a list of all users, and aditional information, will I read the information from 2 DbContext?

Yeah, you probably will, but I don't think it is a big performance deal, because it won't cause any additional database query, considering that you are using only 1 dbcontext at the time.

Please, I need some clear guide because I am very confused right now and I really love to build great code, and I think it's not the case.

Do you like clean code? So, here comes my tip (based on my opinion): FORGET ABOUT ASP.NET IDENTITY! Identity is a bad solution, it is not decoupled, confusing, and unnecessary.

You can create your own login system, using a custom User entity. Use this https://crackstation.net/hashing-security.htm#aspsourcecode for hashing the passwords and this MVC Authentication - Easiest Way to create an OWIN authentication

like image 29
Fabio Luz Avatar answered Sep 28 '22 20:09

Fabio Luz