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

.net core identity 'IsSignedIn' always returns false, even after successful login


I have a .net core 3 identity project that I'm having issues with authentication.

Login.cshtml.cs

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

    if (ModelState.IsValid)
    {
        // Modified base identity to allow login by email or username
        var user = await _userManager.FindByNameAsync(Input.Username);

        if (user == null)
        {
            user = await _userManager.FindByEmailAsync(Input.Username);
        }

        var result = await _signInManager.PasswordSignInAsync(user, Input.Password, Input.RememberMe, lockoutOnFailure: true);

        if (result.Succeeded)
        {
            return LocalRedirect(returnUrl);
        }

        if (result.IsNotAllowed)
        {
            return RedirectToPage("./ConfirmEmail");
        }

        if (result.IsLockedOut)
        {
            return RedirectToPage("./Lockout");
        }

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

    return Page();
}

From the Login page, this line of code: var result = await _signInManager.PasswordSignInAsync(user, Input.Password, Input.RememberMe, lockoutOnFailure: true); returns result.Succeeded, but from the page view, this code always returns false:

@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager

@if (SignInManager.IsSignedIn(User))
{
}

When I step through the code for the IsSignedIn method from the code below, it is failing because principal.Identities.AuthenticationType is always null.

SignInManager.cs

public override bool IsSignedIn(ClaimsPrincipal principal)
{
    if (principal == null)
    {
        throw new ArgumentNullException(nameof(principal));
    }
    return principal?.Identities != null &&
       principal.Identities.Any(i => i.AuthenticationType == IdentityConstants.ApplicationScheme);

}

My first thought is this is a configuration issue in Startup.cs, but I'm not sure what or where the AuthenticationType gets set?

Startup.cs

    public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IDbConnection>((sp) => new SqlConnection(Configuration.GetConnectionString("Database")));
    services.AddIdentity<ApplicationUser, ApplicationRole>()
        .AddDefaultTokenProviders();
        services.ConfigureApplicationCookie(options =>
        {
            options.AccessDeniedPath ="/Account/AccessDenied";
            options.Cookie.Name = "MyApp";
            options.Cookie.HttpOnly = true;
            options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
            options.LoginPath = "/Account/Login";
            // ReturnUrlParameter requires 
            //using Microsoft.AspNetCore.Authentication.Cookies;
            options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
            options.SlidingExpiration = true;
        });
    services.AddMemoryCache();
    services.AddMvc(options => { options.EnableEndpointRouting = false; });
    services.AddRazorPages();
    services.AddSession();
    services.AddTransient<IUserStore<ApplicationUser>, CustomUserStore>();
    services.AddTransient<IRoleStore<ApplicationRole>, CustomRoleStore>();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddSerilog();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();
    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();
    app.UseSession();
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapRazorPages();
    });
}

Solution

  • app.UseMvcWithDefaultRoute() is required to be placed after app.UseAuthentication().

    Since you have used app.UseMvc() in your Configure method , just remove app.UseMvcWithDefaultRoute(); line or place it after app.UseAuthentication() in your code could resolve it.