Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Core 2.0 Identity: SignInManager.IsSignedIn(User) returns false after signing in

I'm having an issue where after creating a user and signing in the SignInManager.IsSignedIn(User) method returns false.

I'm using the new 2.0.0 preview of the SPA Angular CLI template and I've added all the identity config based on what I've read in the docs and using some of the other Visual Studio templates as a guide.

Below is my Startup class.

public class Startup
{
    public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment)
    {
        Configuration = configuration;
        HostingEnvironment = hostingEnvironment;

        //configration
        MyAppConfig.ConnectionString = Configuration.GetConnectionString("DefaultConnection");
        MyAppConfig.Secure = Configuration.GetValue<bool>("App:Secure", true);
    }

    public IConfiguration Configuration { get; }
    private IHostingEnvironment HostingEnvironment { get; set; }
    public IContainer ApplicationContainer { get; private set; }

    private const string EmailConfirmationTokenProviderName = "ConfirmEmail";

    // This method gets called by the runtime. Use this method to add services to the container.
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

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


        IDataProtectionBuilder dataProtectionBuilder = services.AddDataProtection()
            .SetApplicationName("MyApp");

        //data protection
        if (HostingEnvironment.IsDevelopment())
        {
            //for development, do default (intentionally left blank for now)
        }
        else
        {
            //for deployments, protect certificate and persist to azure storage
            //this will allow swapping of web app slots 
            dataProtectionBuilder
                .ProtectKeysWithCertificate("")
                .PersistKeysToAzureBlobStorage(new Uri(""));
        }


        //ssl
        if (!HostingEnvironment.IsDevelopment())
        {
            services.Configure<MvcOptions>(options =>
            {
                options.Filters.Add(new RequireHttpsAttribute());
            });
        }

        var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();

        //anti-forgery, add to all controllers
        services.AddMvc(options => {
            options.Filters.Add(new ValidateAntiForgeryTokenAttribute());
            options.Filters.Add(new AuthorizeFilter(policy));
        });

        services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

        services.AddDbContext<AppDbContext>(options =>
            options.UseSqlServer(MyAppConfig.ConnectionString));

        //identity
        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<AppDbContext>()
            .AddDefaultTokenProviders()
            .AddTokenProvider<ConfirmEmailDataProtectorTokenProvider<ApplicationUser>>(EmailConfirmationTokenProviderName); ;

        services.Configure<IdentityOptions>(options =>
        {
            // Password settings
            options.Password.RequireDigit = true;
            options.Password.RequiredLength = 8;
            options.Password.RequireNonAlphanumeric = true;
            options.Password.RequireUppercase = true;
            options.Password.RequireLowercase = false;
            options.Password.RequiredUniqueChars = 4;

            // Lockout settings
            options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
            options.Lockout.MaxFailedAccessAttempts = 5;
            options.Lockout.AllowedForNewUsers = true;

            // User settings
            options.User.RequireUniqueEmail = true;

            // SignIn settings
            options.SignIn.RequireConfirmedEmail = true;
            options.SignIn.RequireConfirmedPhoneNumber = false;

            options.Tokens.EmailConfirmationTokenProvider = EmailConfirmationTokenProviderName;
        });

        services.ConfigureApplicationCookie(options =>
        {
            // Cookie settings
            options.Cookie.HttpOnly = true;
            options.Cookie.Expiration = TimeSpan.FromHours(1);
            options.SlidingExpiration = true;
        });

        services.Configure<ConfirmEmailDataProtectionTokenProviderOptions>(options =>
        {
            options.TokenLifespan = TimeSpan.FromDays(180);
        });


        //autofac
        var builder = new ContainerBuilder();

        builder.Populate(services);
        builder.RegisterType<AccountService>().As<IAccountService>();
        builder.RegisterType<EmailService>().As<IEmailService>();

        this.ApplicationContainer = builder.Build();

        // Create the IServiceProvider based on the container.
        return new AutofacServiceProvider(this.ApplicationContainer);

    }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAntiforgery antiforgery)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

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

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

        //send anti-forgery cookie with initial SPA page
        //must be before UseSpa() call
        app.Use(next => context =>
        {
            if (
                string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(context.Request.Path.Value, "/index.html", StringComparison.OrdinalIgnoreCase))
            {
                // We can send the request token as a JavaScript-readable cookie, and Angular will use it by default.
                var tokens = antiforgery.GetAndStoreTokens(context);
                context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
                    new CookieOptions() { HttpOnly = false });
            }

            return next(context);
        });

        app.UseSpa(spa =>
        {
            // To learn more about options for serving an Angular SPA from ASP.NET Core,
            // see https://go.microsoft.com/fwlink/?linkid=864501

            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                spa.UseAngularCliServer(npmScript: "start");
                //spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
            }
        });

        //auth & identity
        app.UseAuthentication();
    }

}

Here are the steps I follow to test if the user gets signed in:

  1. Create the user
  2. Validate email (then let the request finish)
  3. Call SignInManager.PasswordSignInAsync() in a new HTTP request which returns Success
  4. Let the request return
  5. Verify the .AspNetCore.Identity.Application cookie is present
  6. Initiate another HTTP request that calls SignInManager.IsSignedIn(User) and it returns false.

I'm not sure what the issue might be as I've read through the documentation at https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity?tabs=visual-studio%2Caspnetcore2x

like image 554
Rob Avatar asked Jan 26 '18 16:01

Rob


1 Answers

Your Middleware executes in the order you declare things in your app. Here is a great resource to help you understand better,

enter image description here

when you call authentication last, this will be the last thing done in the Pipeline:

app.UseAuthentication();

To fix this just put this line above the:

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller}/{action=Index}/{id?}");
});
like image 74
johnny 5 Avatar answered Oct 16 '22 04:10

johnny 5



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!