Blog Home  Home Feed your aggregator (RSS 2.0)  
Mayur's Blog - Customize Microsoft.AspNet.Identity to suit your legacy application
 
# Friday, July 24, 2015

We are thinking to migrate our legacy web application to Asp.Net 5 framework to utilize all the enhancements and good features available.

The biggest road block is Identity system. Our legacy application has its own User and UserRole tables (in database) to Authenticate and Authorize. Asp.Net 5 is based on newer implementation of Identity, which is part of Microsoft.AspNet.Identity and Entityframework.

The out of box implementation using Visual Studio 2015 uses EntityFramework 7 (Beta). We cannot use it and it is still not ready for Production. Our data layer is still EntityFramework but with older version. We don't want to really change this implementation at this moment at least.

It looks like that we need to fully customize Identity framework implemented in Microsoft.AspNet.Identity framework if we want to use it.

Please note that our legacy application does not need anything except log in and log out from Identity system. So basically verifying that the person is authorized and authenticated by given id and password. Additionally, the Identity created after log in should preserve the roles for a given person so that we can use Attributes to decorate our controller and actions to secure it. These attributes will also use Roles for authorization purpose.

The following is an attempt to do this. Actually at this moment I have completed this prototype kind of implementation and was able to  run this successfully. The log in process and log out process worked. The Identity generated (and saved in HttpContext) is capable enough to secure methods using roles.

So here is my implementation goes. It is still kind of an approach to tackle this issue and there is still a room to improve it in terms of both coding and design.

My implementation is based on Asp.Net Beta 5 released with Visual Studio 2015 RTM. It is possible that by the time Asp.NET goes LIVE there may be a few changes and refactoring needed. I don't expect a lot though. Here is my project.json looks like to bring in required references.

Items shown with "Bold and Italic" are required references for Identity framework. 

{
  "webroot": "wwwroot",
  "userSecretsId": "aspnet5-CCClientWeb-8bbc0c70-ab78-4053-a5bf-492342d52f2a",
  "version": "1.0.0-*",

  "dependencies": {
    "Microsoft.AspNet.Authentication.Cookies": "1.0.0-beta5",
    "Microsoft.AspNet.Authentication.Facebook": "1.0.0-beta5",
    "Microsoft.AspNet.Authentication.Google": "1.0.0-beta5",
    "Microsoft.AspNet.Authentication.MicrosoftAccount": "1.0.0-beta5",
    "Microsoft.AspNet.Authentication.Twitter": "1.0.0-beta5",
    "Microsoft.AspNet.Diagnostics": "1.0.0-beta5",
    "Microsoft.AspNet.Diagnostics.Entity": "7.0.0-beta5",
    "Microsoft.AspNet.Identity": "3.0.0-beta5",
    "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-beta5",
    "Microsoft.AspNet.Mvc": "6.0.0-beta5",
    "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-beta5",
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta5",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta5",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta5",
    "Microsoft.AspNet.Tooling.Razor": "1.0.0-beta5",
    "Microsoft.Framework.CodeGenerators.Mvc": "1.0.0-beta5",
    "Microsoft.Framework.Configuration": "1.0.0-beta5",
    "Microsoft.Framework.Configuration.Json": "1.0.0-*",
    "Microsoft.Framework.Logging": "1.0.0-beta5",
    "Microsoft.Framework.Logging.Console": "1.0.0-beta5",    
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-beta5"
  },

  "commands": {
    "ef": "EntityFramework.Commands",
    "gen": "Microsoft.Framework.CodeGeneration",
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
  },

  "frameworks": {
    "dnx451": {
      "dependencies": {
        "CCClients.BusinessService": "1.0.0-*",
        "CCClients.Interfaces": "1.0.0-*",
        "CCClients.Repository": "1.0.0-*",
        "Microsoft.AspNet.Http.Core": "1.0.0-beta4"       
      }
    }
  },

  "exclude": [
    "wwwroot",
    "node_modules",
    "bower_components"
  ],
  "publishExclude": [
    "node_modules",
    "bower_components",
    "**.xproj",
    "**.user",
    "**.vspscc"
  ],
  "scripts": {
    "postrestore": [ "npm install", "bower install" ],
    "prepare": [ "gulp copy" ]
  }
}

1) We need to implement custom classes as shown below. CustomSignInManager and CustomRoleManager inherits from base classes and override required methods. These classes running an engine to drive Identity. Please remember that I am implementing only a bare minimum login functionality to support legacy application. So I really do not have to override many methods from bases classes and do not require implementation of all the interfaces. 

Just to demonstrate how far I can do customization, I have even overridden CheckPassword method (see in CustomUserStore.cs), which allows me to check passwords which are not hashed in the database and stored as raw values. I know that it is not recommended at all but many of the folks forced to support legacy apps not designed properly ard forced to follow this practice and look for a way to find work abounds.

Another thing you may notice is an implementation of CustomUserStore in CustomUserStore.cs. You may see that CustomUserStore class implements many interfaces. This user store actually is a driver for database operations. The implementation here follows "O" of SOLID principles. You may implement as many interfaces as many functionalities you want. In may case I implement IUserStore<CustomIdentityUser>, IUserRoleStore<CustomIdentityUser>, IUserPasswordStore<CustomIdentityUser> because I need Roles. IUserStore and IUserPasswordStore will be needed in any case. However, let's say you want to do account Lockout based on invalid login attempts. In that case you need to implement IUserLockoutStore interface. Identity framework comes with many features and you need to implement required interfaces to take advantage of all. However, if not needed then simply ignoring them would be a wise thing to do to implement a clean and understandable code. 

1)

using Microsoft.AspNet.Identity;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;

namespace CCClientWeb.CustomIdentity
{
    public class CustomClaimsPrincipal : IPrincipal
    {
        private CustomIdentity customIdentity;
        private CustomIdentityUser user;
        public CustomClaimsPrincipal(CustomIdentityUser user)
        {
            customIdentity = new CustomIdentity(IdentityOptions.ApplicationCookieAuthenticationType, true, user.UserName);
            this.user = user;
        }

        public IIdentity Identity
        {
            get
            {
                return customIdentity;
            }
        }

        public bool IsInRole(string role)
        {
            return user.CustomRoles.Any(cr => cr.RoleName == role);
        }
    }
    public class CustomUserClaimsPrincipalFactory : IUserClaimsPrincipalFactory<CustomIdentityUser>
    {
        public async Task<ClaimsPrincipal> CreateAsync(CustomIdentityUser user)
        {
            return await Task.FromResult(new ClaimsPrincipal(new CustomClaimsPrincipal(user)));           
        }
    }
}

2)

using System.Security.Principal;

namespace CCClientWeb.CustomIdentity
{
    public class CustomIdentity : IIdentity
    {
        private string authenticationType;
        private bool isAuthenticated = false;
        private string name;

        public CustomIdentity(string authenticationType, bool isAuthenticated, string name)
        {
            this.authenticationType = authenticationType;
            this.isAuthenticated = isAuthenticated;
            this.name = name;
        }

        public string AuthenticationType
        {
            get
            {
                return authenticationType;
            }
        }

        public bool IsAuthenticated
        {
            get
            {
                return isAuthenticated;
            }
        }

        public string Name
        {
            get
            {
                return name;
            }
        }
    }
}
3)

using Microsoft.AspNet.Identity.EntityFramework;

namespace CCClientWeb.CustomIdentity
{
    public class CustomIdentityRole:IdentityRole<int>
    {
        public override int Id
        {
            get
            {
                return base.Id;
            }

            set
            {
                base.Id = value;
            }
        }

        public override string Name
        {
            get
            {
                return base.Name;
            }

            set
            {
                base.Name = value;
            }
        }  
    }
}

4)

using Microsoft.AspNet.Identity.EntityFramework;
using System.Collections.Generic;
using System.Linq;

namespace CCClientWeb.CustomIdentity
{
    public class CustomIdentityUser:IdentityUser<int>
    {
        public override int Id
        {
            get;
            set;
        }

        public override string UserName
        {
            get;
            set;
        }

        public string Password
        {
            get;
            set;
        }
       
        public List<CustomIdentityUserRole> CustomRoles
        {
            get;
            set;
        }      

        public override string PasswordHash { get; set; }

        public override ICollection<IdentityUserRole<int>> Roles
        {
            get
            {
                return CustomRoles.Cast<IdentityUserRole<int>>().ToList();
            }
        }

        public override ICollection<IdentityUserLogin<int>> Logins
        {
            get
            {
                return base.Logins;
            }
        }

        public override bool TwoFactorEnabled
        {
            get
            {
                return base.TwoFactorEnabled;
            }

            set
            {
                base.TwoFactorEnabled = false;
            }
        }

        public override bool LockoutEnabled
        {
            get
            {
                return base.LockoutEnabled;
            }

            set
            {
                base.LockoutEnabled = false;
            }
        }

    }

    public class CustomIdentityUserRole : IdentityUserRole<int>
    {
        public string RoleName { get; set; }
    }
}

5)

using Microsoft.AspNet.Identity;
using System;
using System.Threading.Tasks;
using System.Threading;

namespace CCClientWeb.CustomIdentity
{
    public class CustomRoleStore : IRoleStore<CustomIdentityRole>
    {
        public Task<IdentityResult> CreateAsync(CustomIdentityRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<IdentityResult> DeleteAsync(CustomIdentityRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
            
        }

        public Task<CustomIdentityRole> FindByIdAsync(string roleId, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<CustomIdentityRole> FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetNormalizedRoleNameAsync(CustomIdentityRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetRoleIdAsync(CustomIdentityRole role, CancellationToken cancellationToken)
        {
            return new Task<string>(() => { return role.Id.ToString(); });
        }

        public Task<string> GetRoleNameAsync(CustomIdentityRole role, CancellationToken cancellationToken)
        {
            return new Task<string>(() => { return role.Name.ToString(); });
        }

        public Task SetNormalizedRoleNameAsync(CustomIdentityRole role, string normalizedName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task SetRoleNameAsync(CustomIdentityRole role, string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<IdentityResult> UpdateAsync(CustomIdentityRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }
}

6)

using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Authentication;
using Microsoft.AspNet.Identity;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using System.Threading.Tasks;

namespace CCClientWeb.CustomIdentity
{
    public class CustomSignInManager : SignInManager<CustomIdentityUser>
    {
        public CustomSignInManager(CustomUserManager userManager,
            IHttpContextAccessor contextAccessor,
            CustomUserClaimsPrincipalFactory claimsFactory,
            IOptions<IdentityOptions> optionsAccessor,
            ILogger<CustomSignInManager> logger) : base(userManager, contextAccessor, claimsFactory, optionsAccessor, null)
        {
            CustomUserManager = userManager;
            CustomContext = contextAccessor.HttpContext;
            CustomUserClaimsPrincipalFactory = claimsFactory;
        }

        CustomUserManager CustomUserManager;
        HttpContext CustomContext;
        CustomUserClaimsPrincipalFactory CustomUserClaimsPrincipalFactory;

        public override async Task<SignInResult> PasswordSignInAsync(CustomIdentityUser user, string password, bool isPersistent, bool lockoutOnFailure)
        {
            if (user.Password == password)
            {
                await SignInAsync(user, isPersistent, string.Empty);
                return SignInResult.Success;
            }

            return SignInResult.Failed;
        }

        public override async Task SignInAsync(CustomIdentityUser user, bool isPersistent, string authenticationMethod = null)
        {
            var userPrincipal = await CustomUserClaimsPrincipalFactory.CreateAsync(user);
            CustomContext.Authentication.SignIn(IdentityOptions.ApplicationCookieAuthenticationScheme, userPrincipal, new AuthenticationProperties { IsPersistent = isPersistent });
        }

    }
}

7)

using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Identity;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace CCClientWeb.CustomIdentity
{
    public class CustomUserManager : UserManager<CustomIdentityUser>
    {
        public CustomUserManager(IUserStore<CustomIdentityUser> store,
            IOptions<IdentityOptions> optionsAccessor,
            IPasswordHasher<CustomIdentityUser> passwordHasher,
            IEnumerable<IUserValidator<CustomIdentityUser>> userValidators,
            IEnumerable<IPasswordValidator<CustomIdentityUser>> passwordValidators,
            ILookupNormalizer keyNormalizer,
            IdentityErrorDescriber errors,
            IEnumerable<IUserTokenProvider<CustomIdentityUser>> tokenProviders,
            ILogger<UserManager<CustomIdentityUser>> logger,
            IHttpContextAccessor contextAccessor):base(store, optionsAccessor, passwordHasher, 
                userValidators, passwordValidators, keyNormalizer, errors, tokenProviders, 
                logger, contextAccessor)
        {
           
        }

        public override async Task<bool> CheckPasswordAsync(CustomIdentityUser user, string password)
        {
            return await new Task<bool>(() => { return user.Password == password; });            
        }
    }  
}

8)

using Microsoft.AspNet.Identity;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using CC.Interfaces.RepositoryServices;
using System.Threading;

namespace CCClientWeb.CustomIdentity
{
    public partial class CustomUserStore : IUserStore<CustomIdentityUser>, IUserRoleStore<CustomIdentityUser>, IUserPasswordStore<CustomIdentityUser>
    {
        private IdentityService service;
        private IPasswordHasher<CustomIdentityUser> passwordHasher;

        public CustomUserStore(ILoginRepositoryService loginRepositoryService, IPasswordHasher<CustomIdentityUser> passwordHasher)
        {
            service = new IdentityService(loginRepositoryService, passwordHasher);
            this.passwordHasher = passwordHasher;
        }
        public Task<IdentityResult> CreateAsync(CustomIdentityUser user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<IdentityResult> DeleteAsync(CustomIdentityUser user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<CustomIdentityUser> FindByIdAsync(string userId, CancellationToken cancellationToken)
        {
            return service.GetUserByIdAsync(userId);
        }

        public Task<CustomIdentityUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
        {
            return service.GetUserByUserNameAsync(normalizedUserName);
        }

        public Task<string> GetNormalizedUserNameAsync(CustomIdentityUser user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetUserIdAsync(CustomIdentityUser user, CancellationToken cancellationToken)
        {
            return new Task<string>(() => { return user.Id.ToString(); });
        }

        public Task<string> GetUserNameAsync(CustomIdentityUser user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task SetNormalizedUserNameAsync(CustomIdentityUser user, string normalizedName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task SetUserNameAsync(CustomIdentityUser user, string userName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<IdentityResult> UpdateAsync(CustomIdentityUser user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        #region IDisposable Support
        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: dispose managed state (managed objects).
                }

                // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
                // TODO: set large fields to null.

                disposedValue = true;
            }
        }

        // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
        // ~CustomUserStore() {
        //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        //   Dispose(false);
        // }

        // This code added to correctly implement the disposable pattern.
        public void Dispose()
        {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose(true);
            // TODO: uncomment the following line if the finalizer is overridden above.
            // GC.SuppressFinalize(this);
        }
        #endregion

   
        public Task AddToRoleAsync(CustomIdentityUser user, string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<IList<string>> GetRolesAsync(CustomIdentityUser user, CancellationToken cancellationToken)
        {
            return service.GetUserRolesAsync(user);
        }

        public Task<IList<CustomIdentityUser>> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<bool> IsInRoleAsync(CustomIdentityUser user, string roleName, CancellationToken cancellationToken)
        {
            return service.IsUserInRoleAsync(user, roleName);
        }

        public Task RemoveFromRoleAsync(CustomIdentityUser user, string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
   
        public Task<string> GetPasswordHashAsync(CustomIdentityUser user, CancellationToken cancellationToken)
        {
            return service.GetPasswordHashAsync(user);
        }

        public Task<bool> HasPasswordAsync(CustomIdentityUser user, CancellationToken cancellationToken)
        {
            return service.HasPasswordAsync(user);
        }

        public Task SetPasswordHashAsync(CustomIdentityUser user, string passwordHash, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }
}

9)

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using sc = System.Security.Claims;
using CC.Interfaces.RepositoryServices;

namespace CCClientWeb.CustomIdentity
{
    public class IdentityService
    {
        ILoginRepositoryService _loginRepSrv = null;
        IPasswordHasher<CustomIdentityUser> passwordHasher = null;

        public IdentityService(ILoginRepositoryService loginRepository, IPasswordHasher<CustomIdentityUser> passwordHasher)
        {
            _loginRepSrv = loginRepository;
            this.passwordHasher = passwordHasher;
        }

        public async Task<CustomIdentityUser> GetUserByUserNameAsync(string userName) 
        {
            var login = await _loginRepSrv.FirstOrDefaultAsync(l => l.LoginName == userName);
            if (login == null) return null;
            var userId = login.CompanyId == null ? login.EmployeeId.Value : login.CompanyId.Value;
            return new CustomIdentityUser 
                { Id = userId, 
                    Password = login.LoginPassword, 
                    UserName = login.LoginName, 
                    CustomRoles = login.LoginsRoles.Select(lr => new CustomIdentityUserRole { RoleId = lr.RoleId, UserId = userId, RoleName = lr.Role.RoleName }).ToList()  
                };
        }

        public async Task<CustomIdentityUser> GetUserByIdAsync(string userId)
        {
            var id = int.Parse(userId);
            var login = await _loginRepSrv.FirstOrDefaultAsync(l => (l.EmployeeId == id && l.CompanyId == null) || (l.CompanyId == id && l.EmployeeId == null));
            var roles = login.LoginsRoles.Select(lr => new CustomIdentityUserRole { RoleId = lr.RoleId, UserId = id, RoleName = lr.Role.RoleName }).ToList();

            return new CustomIdentityUser
            {
                Id = login.CompanyId == null ? login.EmployeeId.Value : login.CompanyId.Value,
                Password = login.LoginPassword,
                UserName = login.LoginName,
                CustomRoles = roles
            };
        }

        public async Task<CustomIdentityUser> FindByNameAsync(string userName) 
        {
            return await GetUserByUserNameAsync(userName);
        }

        public async Task<IList<string>> GetUserRolesAsync(CustomIdentityUser user) 
        {
            var login = await _loginRepSrv.FirstOrDefaultAsync(l => (l.EmployeeId == user.Id && l.CompanyId == null) || (l.CompanyId == user.Id && l.EmployeeId == null));
            return login.LoginsRoles.Select(lr => lr.Role.RoleName).ToList();            
        }

        public async Task<bool> IsUserInRoleAsync(CustomIdentityUser user, string role)
        {
            List<string> roles = await GetUserRolesAsync(user) as List<string>;

            if (roles.Contains(role))
            {
                return true;
            }
            else
            {
                return false;
            }

        }

        public Task AddClaimAsync(CustomIdentityUser user, System.Security.Claims.Claim claim) 
        {
            return new Task(() => { 
            
            });
        }

        public Task<IList<sc.Claim>> GetClaimsAsync(CustomIdentityUser user) 
        {
            return new Task<IList<sc.Claim>>(() => {
                List<sc.Claim> claims = new List<sc.Claim>();
                claims.Add(new sc.Claim(user.CustomRoles.FirstOrDefault().RoleName, user.UserName));                
                return claims as IList<sc.Claim>;
            });            
        }

        public Task RemoveClaimAsync(CustomIdentityUser user, System.Security.Claims.Claim claim)
        {
            return new Task(() => {});
        }

        public Task<string> GetSecurityStampAsync(CustomIdentityUser user) 
        {
            return Task.FromResult("GetSecurityStampAsync");      
        }

        public Task SetSecurityStampAsync(CustomIdentityUser user, string stamp) 
        {
            return new Task(() => { });
        }

        public async Task<string> GetPasswordHashAsync(CustomIdentityUser user) 
        {
            return await Task.FromResult(passwordHasher.HashPassword(user, user.Password));
        }

        public Task<bool> HasPasswordAsync(CustomIdentityUser user) 
        {
            return Task.FromResult(true);
        }
        
        
    }
}

Once classes are written, we can prepare start-up pipeline by adding the following values in Startup.cs. I had to made sure that Authorization configuration is added before MVC as shown below.

app.UseIdentity() is also needed in Configure method in Startup.cs

Basically that is pretty much needed to wire up things to customize Identity in Asp.NET 5.

As you may notice that IndentityService.cs is my wrapper to repositories in Data layer project. I have put in reference to this project in Web project and injected services in Startup.cs. You may see that one of them is ILoginServiceRepository. This class has several methods which allows me to search users and roles.

My LogIn action in controller looks like the following.

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Authorization;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Mvc;
using CCClientWeb.Models;
using CCClientWeb.CustomIdentity;
using CC.Interfaces.RepositoryServices;

namespace CCClientWeb.Controllers
{
    [Authorize]
    public class AccountController : Controller
    {
        public AccountController(CustomUserManager userManager, CustomSignInManager signInManager)
        {
            UserManager = userManager;
            SigninManager = signInManager;            
        }

        public CustomUserManager UserManager { get; private set; }

        public CustomSignInManager SigninManager { get; private set; }

        private ILoginRepositoryService loginRepositoryService;

        private IdentityService identityService;

        //
        // GET: /Account/Login
        [HttpGet]
        [AllowAnonymous]
        public IActionResult Login(string returnUrl = null)
        {            
            ViewBag.ReturnUrl = returnUrl;
            return View();
        }

        //
        // POST: /Account/Login
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
        {
            ViewBag.ReturnUrl = returnUrl;
            if (ModelState.IsValid)
            {
                // This doesn't count login failures towards account lockout
                // To enable password failures to trigger account lockout, set shouldLockout: true
                var result = await SigninManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, false);
                if (result.Succeeded)
                {
                    return RedirectToLocal(returnUrl);
                }

                ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                return View(model);
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }
}

As this implementation of Identity framework in Asp.Net 5 is a brand new, I had to put in some research. Thankfully, Asp.Net is open source now. I was able to download the code from GithHub (https://github.com/aspnet/Identity) and able to look at it to understand to implement this customization.

As I am injecting repositories into my web project, it really does not matter how I implement my repositories. It is a black box to Identity framework. As loon as it has required methods to do the job, it would work. So this way I was also able to reuse my old code.

I hope that this work may be useful to someone who may be looking forward to migrate his/her legacy applications to Asp.NET 5 but still want to re-use most of existing code base.

Friday, July 24, 2015 10:36:34 PM UTC  #       | 
Copyright © 2022 Mayur Bharodia. All rights reserved.
DasBlog 'Portal' theme by Johnny Hughes.
Pick a theme: