In this article we will demonstrate how to provide authentication to ASP .NET 5 applications using ASP .NET Identity with Entity Framework 7.
Adding Packages
Add the following package to your ASP .NET project. This will automatically pull in additional required dependencies for ASP .NET Identity.
project.json
1 2 3 4 5 6 7 8 9 10 11 |
{ ... "dependencies": { .. "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-rc1-final" ... } ... } |
Application Design Concerns
Later in this tutorial we will see that in order to use ASP .NET Identity you have to derive your database context from IdentityDbContext instead of DbContext. This will then generate the corresponding tables in your database. IdentityDbContext is a class from Microsoft.AspNet.Identity.EntityFramework which in turn has a dependency to ASP .NET itself.
In most of my applications I am using a database access layer for a cleaner application design. This means the DbContext is stored in a separate project. If I now want to derive my database context from IdentityDbContext, I had to add a dependency to ASP .NET libraries in my data access layer (bad design). This project does not have a dependency to ASP .NET and should not have that kind of dependency in the future.
What I ended up doing is, that I kept my data access layer for domain specific entities as is and introduced a second database context within the ASP .NET project for user management and authentication. This new IdentityDbContext uses the same database and because it lies within the ASP .NET project does not introduce new dependencies to my original data access layer.
I have not seen a tutorial so far which addresses this application design issue. If someone can tell me how they solved this problem please leave me some comment below.
Creating Identity Database Context
Since I wanted to be able to add additional user information later on, I derived my own AppUser class from IdentityUser.
1 2 3 |
public class AppUser: IdentityUser { } |
Then I created a new AppIdentityDbContext within the ASP .NET project.
1 2 3 4 5 6 7 8 9 10 |
public class AppIdentityDbContext : IdentityDbContext<AppUser> { protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.HasDefaultSchema("AppIdentity"); } } |
Since I use the same database for 2 database contexts, I at least specified a separate Default Schema for the IdentityDbContext. This way the tables automatically created by it can more easily be identified.
In order to automatically generate the corresponding tables within the database, you now can either use the command dnx ef (see Entity Framework Setup) or call new AppIdentityDbContext().Database.Migrate() somewhere in the code.
Configuring ASP .NET Identity
Now we have to configure ASP .NET to use our previously generated AppIdentityDbContext. We therefore have to do add the following line to our Startup.cs class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public void ConfigureServices(IServiceCollection services) { ... services.AddEntityFramework() .AddSqlServer() .AddDbContext<AppIdentityDbContext>( options => { options.UseSqlServer(Configuration["Data:ConnectionString"]); }); services.AddIdentity<AppUser, IdentityRole>( a => { a.Password.RequireUppercase = false; a.Password.RequireNonLetterOrDigit = false; }) .AddEntityFrameworkStores<AppIdentityDbContext>(); ... } |
This tells the AppIdentityDbContext which database to use and configures ASP .NET Identity to use AppIdentityDbContext as the database context. In addition to that I removed a couple of default restrictions for the passwords.
Now the only thing left for setting up ASP .NET Identity is adding and additional line of code in the Configure Method of Startup.cs.
1 2 3 4 5 6 |
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { ... app.UseIdentity(); ... } |
Seeding the Database with an Initial User
In order to put an initial user into the database I created a new UserSeeder class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class UserSeeder { private readonly AppIdentityDbContext _context; private readonly UserManager<AppUser> _userManager; public FacesSeeder(AppIdentityDbContext context, UserManager<AppUser> userManager ) { _context = context; _userManager = userManager; } public async Task Seed() { if (!await _context.Users.AnyAsync()) { var user = new AppUser() { UserName = "admin", Email = "admin@gmail.com" }; var res = await _userManager.CreateAsync(user, "admin"); } } } |
We will provide the constructor parameters via Dependency Injection. The Seed method will check if there are any users in the database and if there are none create a default admin user. The second parameter of the CreateAsync method is the password for the user.
Since UserManager methods are async the Seed method has to be async as well.
Calling the UserSeeder
In order to use Dependency Injection for the 2 constructor parametersof the seeder, we first have to register the UserSeeder as a service in Startup.cs.
1 2 3 4 5 6 |
public void ConfigureServices(IServiceCollection services) { ... services.AddTransient<UserSeeder>(); ... } |
After registering the UserSeeder, we can use it in the Configure method of Startup.cs by appending it as a new parameter. It will automatically be provided by the Dependency Injection.
1 2 3 4 5 |
public void Configure(..., UserSeeder userSeeder) { ... userSeeder.Seed().Wait(); } |
Summary
This article demonstrates how to set up authentication for ASP .NET Identity and Entity Framework. In the next article, I will show how to check in a controller if a user is authenticated and not.