Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SignInManager.PasswordSignInAsync() succeeds, but User.Identity.IsAuthenticated is false

I'm new to ASP.Net Core and trying to create an user authentication system. I'm using ASP.Net Core Identity user management. I have the below code for logging in an user.

/Areas/Identity/Pages/Account/Login.cshtml.cs

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: true);

        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            _logger.LogInformation(User.Identity.IsAuthenticated.ToString());

            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();
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddDbContext<ApplicationDbContext>(options =>
    {
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
    });

    services.AddDefaultIdentity<IdentityUser>().AddEntityFrameworkStores<ApplicationDbContext>();

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    // Use a unique identity cookie name rather than sharing the cookie across applications in the domain.
    services.ConfigureApplicationCookie(options =>
    {
        options.Cookie.Name = Configuration["CookieName"];
    });

    // Add SAML SSO services.
    services.AddSaml(Configuration.GetSection("SAML"));

    services.AddTransient<IPasswordHasher<IdentityUser>, CustomPasswordHasher>();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseAuthentication();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            "default",
            "{controller=Home}/{action=Index}/{id?}");
    });
}

I need to set some attributes in the cookies when the user logs in, but I always get User.Identity.IsAuthenticated false even if it shows User logged in in the logger and PasswordSignInAsync succeeds. How to log in the user inside OnPostAsync ?

N.B: User is logged in when redirected to home page after PasswordSignInAsync succeeds.

I've already checked this question but it didn't solve my issue.

like image 495
MD. Khairul Basar Avatar asked Feb 06 '19 06:02

MD. Khairul Basar


2 Answers

For User.Identity.IsAuthenticated, it only works for sub-request after PasswordSignInAsync.

You could try options below:

  1. Redirect to another action to set the cookies.

    public class LoginModel : PageModel
    {
        private readonly SignInManager<IdentityUser<int>> _signInManager;
        private readonly ILogger<LoginModel> _logger;
    
        public LoginModel(SignInManager<IdentityUser<int>> signInManager, ILogger<LoginModel> logger)
        {
            _signInManager = signInManager;
            _logger = logger;
        }
    
        //rest code
    
        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: true);
                if (result.Succeeded)
                {
                    _logger.LogInformation("User logged in.");
                    return LocalRedirect($"~/Identity/Account/Login?handler=SetIdentity&returnUrl={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();
        }
    
        public async Task<IActionResult> OnGetSetIdentityAsync(string returnUrl)
        {
            _logger.LogInformation(User.Identity.IsAuthenticated.ToString());
    
            return LocalRedirect(returnUrl);
        }
    }
    
  2. Use _signInManager.CreateUserPrincipalAsync

    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: true);
            if (result.Succeeded)
            {
                var user = await _signInManager.UserManager.FindByEmailAsync(Input.Email);
                var userPrincipal = await _signInManager.CreateUserPrincipalAsync(user);
                var identity = userPrincipal.Identity;
                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();
    }
    
like image 180
Edward Avatar answered Nov 13 '22 17:11

Edward


Just answering for the Future Searchers.
I had this Problem before.

My Problem was That The Cookie for the Identity after Login Was There in the Browser but the Application Couldn't Read it, I just Added Both app.UseAuthorization(); and app.UseAuthentication(); to my program.cs then I read the Cookies just fine.

    [HttpPost]
    public async Task<IActionResult> Login(string username,string password)
    {
        if (User.Identity.IsAuthenticated)
        {
            return Redirect("/");
        }

        if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(username))
        {
            var result = await signInManager.PasswordSignInAsync(username, password, true,false);
            if (!result.Succeeded)
            {
                ModelState.AddModelError("Wrong", "Username or Password are wrong");
            }
            else {
                return Redirect("/");
            }
        }
        else {
            ModelState.AddModelError("Cant Be Empty", "username and password can not be empty.");
        }
        return View();
    }
like image 1
Ali.h Avatar answered Nov 13 '22 17:11

Ali.h