When you are building a website you will sooner or later want to build in some kind of Identification and Authorisation control to make sure not everyone can change your website or see sensitive information. In this tutorial I will show you how to build in simple Identification and Authorisation in your ASP.NET MVC website.
In this tutorial we start with an empty mvc project. You could also choose to start with an non empty ASP.NET MVC Application when creating a new project but I want to show you which files and references are required for ASP.NET Identity and this non empty project contains much more then only Identification and Authorisation.
Add required references
First lets start with adding all required references. Open the Nuget Package Managerand add all assemblies shown below:
Required assemblies
- Microsoft.Owin.Host.SystemWeb
- Microsoft.AspNet.Identity.Core
- Microsoft.AspNet.Identity.OWIN
- Microsoft.AspNet.Identity.EntityFramework
Adding ASP.NET Identification
First I will sum up all files that are required for ASP.NET Identification. After that I will explain their purpose one by one.
Required files
- Startup.cs
- Startup.Auth
- IdentityModels
- IdentityConfig
- AccountController
- AccountViewModels
- Views/Account
Startup.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
using Microsoft.Owin; using Owin; [assembly: OwinStartupAttribute(typeof(NH.Backend.Startup))] namespace NH.Backend { public partial class Startup { public void Configuration(IAppBuilder app) { ConfigureAuth(app); } } } |
This file is located in the root of your application and is required. Every OWIN application has a startup class where you specify components for the application pipeline. OWIN is a specification that defines an API for framework and servers to cooperation. The point of OWIN is to decouple server and application. For example, ASP.NET Identity uses OWIN security, therefore they need to have a startup class, that is defined in “Startup.cs” file.
App_Start/Startup.Auth.cs
This file is an extension (other partial) of the Startup class in Startup.cs. It contains the method ConfigureAuth which is called in the file Startup.cs. If you just need basic functionality the file could look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public partial class Startup { // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 public void ConfigureAuth(IAppBuilder app) { // Configure the db context, user manager and signin manager to use a single instance per request app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create); // Enable the application to use a cookie to store information for the signed in user // and to use a cookie to temporarily store information about a user logging in with a third party login provider // Configure the sign in cookie app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { // Enables the application to validate the security stamp when the user logs in. // This is a security feature which is used when you change a password or add an external login to your account. OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) } }); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process. app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5)); // Enables the application to remember the second login verification factor such as phone or email. // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from. // This is similar to the RememberMe option when you log in. app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie); } } |
Models/IdentityModels.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more. public class ApplicationUser : IdentityUser { public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager) { // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); // Add custom user claims here return userIdentity; } } public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("DatabaseContext", throwIfV1Schema: false) { } public static ApplicationDbContext Create() { return new ApplicationDbContext(); } } |
App_Start/IdentityConfig.cs
In this file you configure the application user manager and signin manager.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
// Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application. public class ApplicationUserManager : UserManager<ApplicationUser> { public ApplicationUserManager(IUserStore<ApplicationUser> store) : base(store) { } public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) { var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>())); // Configure validation logic for usernames manager.UserValidator = new UserValidator<ApplicationUser>(manager) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true }; // Configure validation logic for passwords manager.PasswordValidator = new PasswordValidator { RequiredLength = 6, RequireNonLetterOrDigit = true, RequireDigit = true, RequireLowercase = true, RequireUppercase = true, }; // Configure user lockout defaults manager.UserLockoutEnabledByDefault = true; manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5); manager.MaxFailedAccessAttemptsBeforeLockout = 5; manager.EmailService = new EmailService(); var dataProtectionProvider = options.DataProtectionProvider; if (dataProtectionProvider != null) { manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity")); } return manager; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// Configure the application sign-in manager which is used in this application. public class ApplicationSignInManager : SignInManager<ApplicationUser, string> { public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager) : base(userManager, authenticationManager) { } public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user) { return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager); } public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context) { return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication); } } |
And probably you want an EmailService aswell when one of your users forget their password.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class EmailService : IIdentityMessageService { public Task SendAsync(IdentityMessage message) { string fromAddress = "xxxx@gmail.com"; string passwd = "xxxxxx"; var smtp = new SmtpClient { Host = "smtp.gmail.com", Port = 587, EnableSsl = true, DeliveryMethod = SmtpDeliveryMethod.Network, UseDefaultCredentials = false, Credentials = new NetworkCredential(fromAddress, passwd) }; smtp.SendCompleted += (s, e) => { smtp.Dispose(); }; var mail = new MailMessage(fromAddress, message.Destination); mail.Subject = message.Subject; mail.Body = message.Body; return smtp.SendMailAsync(mail); } } |
ViewModels/AcountViewModel.cs
For this basic authentication setup this viewmodel can look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
public class LoginViewModel { [Required] [Display(Name = "Email")] [EmailAddress] public string Email { get; set; } [Required] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } [Display(Name = "Remember me?")] public bool RememberMe { get; set; } } public class RegisterViewModel { [Required] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "Confirm password")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] public string ConfirmPassword { get; set; } } public class ResetPasswordViewModel { [Required] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "Confirm password")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] public string ConfirmPassword { get; set; } public string Code { get; set; } } public class ForgotPasswordViewModel { [Required] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } } |
AccountController and Views
I recommend you to use the one in the MVC sample project. If you create a new (non-empty) MVC project you will get this class and views for free. Strip all methods you don’t need and adjust the views to your needs.
Now you should be able to compile your project and you can try to login by navigating to /Account/Login
where you save the data?, i need to change the default DB, for my db, can u help me?; i mean my tables, for example USER, for save, user_id, email, etc
Thaaaaaaaank you
Full source application like WingToys but in MVC ?