Search code examples
authenticationasp.net-coreasp.net-identityidentityserver4asp.net-authorization

ASP Core 3 react template, HttpContext.User.IsAuthenticated() returns False after login


After working on my project for a while, I released the HttpContext.User.IsAuthenticated() returns False after login and I need to know where I should look for the mistake I made that cause this problem. This is the Login, OnPost method.

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    if (ModelState.IsValid)
    {
        var user = _userManager.Users.FirstOrDefault(u => u.StudentNumber == Input.StudentNumber.ToString());
        if (!(user is null) && await _userManager.CheckPasswordAsync(user, Input.Password))
            await _signInManager.SignInAsync(user, Input.RememberMe);
        var isUserAuthenticated = HttpContext.User.IsAuthenticated();
        return Redirect(returnUrl);
    }

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

The ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
{
     services.AddAutoMapper();

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

     services.AddDefaultIdentity<ApplicationUser>(option=>option.Password.RequireNonAlphanumeric=false)
                .AddEntityFrameworkStores<ApplicationDbContext>();

     services.AddIdentityServer()
                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

     services.AddAuthentication()
                .AddIdentityServerJwt();

     services.AddMvc(options => options.EnableEndpointRouting = false)
                .AddNewtonsoftJson();

            // In production, the React files will be served from this directory
     services.AddSpaStaticFiles(configuration =>
     {
           configuration.RootPath = "ClientApp/build";
     });
}

The Configure method.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
   if (env.IsDevelopment())
   {
       app.UseDeveloperExceptionPage();
       app.UseDatabaseErrorPage();
   }
   else
   {
       app.UseExceptionHandler("/Error");
       // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
       app.UseHsts();
   }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseSpaStaticFiles();

    app.UseAuthentication();
    app.UseIdentityServer();

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

    app.UseSpa(spa =>
    {
        spa.Options.SourcePath = "ClientApp";

        if (env.IsDevelopment())
        {
            spa.UseReactDevelopmentServer(npmScript: "start");
        }
    });
}

Solution

  • SignInManager.SignInAsync() only creates the cookie for the given user. This method would not set HttpContext.User.

    But in the next request which has the cookie you can access HttpContext.User after AuthenticationMiddleware and HttpContext.User.IsAuthenticated() should be true.

    AuthenticationMiddleware always try to authenticate user with the default scheme and since you have AddIdentityServer after AddDefaultIdentity, identity server is becoming your default scheme, but when you call SignInManager.SignInAsync the Identity scheme is triggered.

    To sum up, with this configuration your AuthenticationMiddleware always tries to authenticate request for IdentityServer and if you want other scheme for you apis you should use [Authorize(AuthenticationSchemes = "Identity.Application")].

    P.S. Identity.Application is authenticatio scheme for ASP.NET Identity