Search code examples
c#asp.net-coreasp.net-core-identity

Asp.Net Core - Identity SignInManager - How to signIn with an additional conditions in order for users to login (ex: ClientId, UserName and Password))


How to sign-in with an extra condition, in Asp.Net Core - Identity SignInManager

Example i want to check and validate ClientId, UserName and Password for sign-in.

some thing like this

var result = await SignInManager.PasswordSignInAsync(model.ClientId, model.Email, model.Password, model.RememberMe, shouldLockout: false);

Please see the full code bellow

        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            returnUrl = returnUrl ?? Url.Content("~/");

            if (ModelState.IsValid)
            {
                // This doesn't count login failures towards account lockout
                // To enable password failures to trigger account lockout, set lockoutOnFailure: true
                var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);

                if (result.Succeeded)
                {
                    _logger.LogInformation("User logged in.");
                    return LocalRedirect(returnUrl);
                }
                if (result.RequiresTwoFactor)
                {
                    return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
                }
                if (result.IsLockedOut)
                {
                    _logger.LogWarning("User account locked out.");
                    return RedirectToPage("./Lockout");
                }
                else
                {
                    ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                    return Page();
                }
            }

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


Solution

  • Their is more than one solution found, and i picked to extend the signInManager.
    The above answer by @Markuzy is also correct, https://stackoverflow.com/a/61211905/13305109

    Here is my code

    public class MySignInManager<TUser> : SignInManager<MyUser> where TUser : class
    {
        private readonly UserManager<MyUser> _userManager;
        private readonly MyContext _dbContext;
        private readonly IHttpContextAccessor _contextAccessor;
    
        public MySignInManager(UserManager<MyUser> userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory<MyUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor, ILogger<SignInManager<MyUser>> logger, MyContext dbContext, IAuthenticationSchemeProvider schemeProvider, IUserConfirmation<MyUser> confirmation) : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemeProvider, confirmation)
        {
            _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
            _contextAccessor = contextAccessor ?? throw new ArgumentNullException(nameof(contextAccessor));
            _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
        }
    
        public override async Task<SignInResult> PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure)
        {
            SignInResult signInResult = new SignInResult();
    
            //Login not allowed - ClientId required to login
            return await Task.FromResult(signInResult);
        }
    
        public async Task<SignInResult> PasswordSignInAsync(string clientId, string userName, string password, bool isPersistent, bool lockoutOnFailure)
        {      
            if(CheckIsClientIdValid(username, password))
            {
                var result = await base.PasswordSignInAsync(userName, password, isPersistent, lockoutOnFailure);
                return result;
            }
            else
            {
                SignInResult result = await Task.FromResult(new SignInResult());
                //Login not allowed - ClientId mismatch
                return result;
            }            
        }
    }
    

    And add bellow code in Startup.cs according to the order

    services.AddSignInManager<MySignInManager<MyUser>>();
    

    And use as

    var result = await _signInManager.PasswordSignInAsync(Input.ClientId, Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);