locked
LoginPath not working in ASP.NET Core 3.1 app RRS feed

  • Question

  • User-292413934 posted

    So I'm trying to override the default path for login on an ASP.NET Cor 3.1 project however when I try to set it in startup the framework just ignores it. I've had to put a action at the default route to catch it so I can redirect to the route I want to use but I'd like to know why my configuration is not being applied. Here is my ConfigureServices code:

            public void ConfigureServices(IServiceCollection services)
            {
                var appSettings = Configuration.GetSection("AppSettings");
                services.Configure<AppSettings>(appSettings);
    
                services.AddScoped<ApplicationContext, WebApp>();
                services.AddScoped<AccountService>();
                services.AddHttpContextAccessor();
    
                services.AddDbContext<DataContext>(ServiceLifetime.Scoped);
                services.AddDbContext<IdentityDataContext>(ServiceLifetime.Scoped);
    
                services.AddIdentity<IdentityUser, IdentityRole>()
                    .AddEntityFrameworkStores<IdentityDataContext>()
                    .AddDefaultTokenProviders();
    
                services.Configure<IdentityOptions>(options =>
                {
                    options.Password.RequiredLength = 6;
                    options.Password.RequireDigit = false;
                    options.Password.RequireNonAlphanumeric = false;
                    options.Password.RequireUppercase = false;
                    options.Password.RequireLowercase = false;
                    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
                    options.Lockout.MaxFailedAccessAttempts = 5;
                    options.User.RequireUniqueEmail = true;
                });
    
                services.ConfigureApplicationCookie(options =>
                {
                    options.Cookie.HttpOnly = true;
                    options.Cookie.IsEssential = true;
                    options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
                    options.ExpireTimeSpan = TimeSpan.FromDays(7);
                    options.SlidingExpiration = true;
                    options.LoginPath = "/signin";
                    options.LogoutPath = "/signout";
                });
    
                services.AddDistributedMemoryCache();
    
                services.AddSession(options =>
                {
                    options.Cookie.HttpOnly = true;
                    options.Cookie.IsEssential = true;
                    options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
                    options.Cookie.MaxAge = TimeSpan.FromDays(7);
                });
    
                services.AddBundles(options =>
                {
                    options.AppendVersion = true;
                });
    
                services.AddControllersWithViews(options =>
                {
                    options.Filters.Add(typeof(ExceptionHandlerAttribute));
                })
                .AddNewtonsoftJson(options =>
                {
                    options.SerializerSettings.ContractResolver = new ConditionalJsonContractResolver();
                });
    
                services.AddRazorPages();
    
                services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext?.User);
            }

    And if it matters my Configure code:

            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
    
                app.UseHttpsRedirection();
                app.UseStaticFiles();
                app.UseRouting();
                app.UseAuthentication();
                app.UseMiddleware<AuthenticationMiddleware>();
                //app.UseAuthorization();
                app.UseSession();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Home}/{action=Index}/{id?}");
                    endpoints.MapRazorPages();
                });
            }

    Friday, February 26, 2021 6:10 PM

All replies

  • User475983607 posted

    It is not clear what steps you have performed to get to this point.  Identity is a Razor Class Library in 3.1.  My best guess is the RCL configuration is taking precedence. 

    See scaffolding Identity.

    https://docs.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-5.0&tabs=visual-studio

    Friday, February 26, 2021 6:21 PM
  • User-292413934 posted

    If I remember right I didn't scaffold Identity and added Identity after the fact. How would I override the RCL configuration? I'm sure there must be something in code or configuration to override this.

    Friday, February 26, 2021 6:25 PM
  • User1686398519 posted

    Hi  scott.wilson,

    I want to confirm some things with you:

    1.             app.UseAuthentication();
                  app.UseMiddleware<AuthenticationMiddleware>();
                  //app.UseAuthorization();
      1. When I use your code for testing, the following error appears.Did you report an error when you commented out "app.UseAuthorization();"?
    2. Is "signin" a razor pages?"

    Best Regards,

    YihuiSun

    Thursday, March 4, 2021 8:58 AM
  • User-292413934 posted

    Just comment out the line:

    app.UseMiddleware<AuthenticationMiddleware>();

    And uncomment out:

    //app.UseAuthorization();

    The AuthenticationMiddleware is just my own custom implementation of Authorization middleware.

    Thursday, March 4, 2021 5:56 PM
  • User1686398519 posted

    Hi scott.wilson, 

    I also asked you a question before:

    • Is "signin" a razor page?"
    • If "signin" is not a razor page, you can't find the corresponding page if you set it like this.
    • If "signin" is a razor page, you need to create a folder called "Pages" and place the signin under the "Pages" folder.

    Best Regards,

    YihuiSun

    Tuesday, March 9, 2021 8:57 AM
  • User-292413934 posted

    Yes, it's a Razor page in the Home directory. I currently have the below hack in place in an AccountController class that redirects to the route that I want until I can figure out how to override the default route. I can't believe it's this difficult to override without going through through all this heavy handed scaffolding. 

            public IActionResult Login()
            {
                return RedirectToAction("SignIn", "Home", new { returnUrl = "dashboard" });
            }

    Tuesday, March 9, 2021 6:25 PM
  • User1686398519 posted

    Hi scott.wilson, 

    it's a Razor page in the Home directory.

    You seem to confuse the routing of ASP.NET Core MVC and ASP.NET Core Razor Pages.

    RedirectToAction("SignIn", "Home", new { returnUrl = "dashboard" });

    In the Razor Pages project, the URL is matched based on the folder where the file is located (in Pages).

    • In other words, if you are creating a Razor page, then you need to write the correct URL based on the location of the SignIn file. You can refer to my last answer.

    But according to the code you provided, what you created is an MVC View. In MVC projects, the URL is usually matched according to "/controller/action".You need to modify your code like this:

    • "Home" is the Controller Name
    • "SignIn" is the Action Name
    options.LoginPath = "/Home/SignIn";

    You can check the links below to help you understand the solution I gave.

    1. Razor Pages Routing
    2. Routing to controller actions in ASP.NET Core
    3. What about the MVC Framework?

    Best Regards,

    YihuiSun

    Wednesday, March 10, 2021 9:43 AM
  • User-292413934 posted

    Unfortunately changing that still doesn't do the trick.

    Wednesday, March 10, 2021 4:58 PM
  • User475983607 posted

    Unfortunately changing that still doesn't do the trick.

    I cannot reproduce this behavior with the default setup.  I assume you have custom code that is causing this issue.

    Wednesday, March 10, 2021 7:49 PM
  • User-292413934 posted

    Other than what would be in startup what custom code would have any effect on this? This is why I get so frustrated with frameworks that try to do too much for you. Wish we could just go back to classic ASP.NET MVC, everything was so much more straightforward.

    Wednesday, March 10, 2021 8:13 PM
  • User475983607 posted

    scott.wilson@res

    Other than what would be in startup what custom code would have any effect on this? This is why I get so frustrated with frameworks that try to do too much for you. Wish we could just go back to classic ASP.NET MVC, everything was so much more straightforward.

    It is straight forward.   Unfortunately, I cannot reproduce your results. 

    Can you share the source code for the following?

    app.UseMiddleware<AuthenticationMiddleware>();

    Maybe create a new test project and focus only on the login.  

    Thursday, March 11, 2021 12:40 AM
  • User-292413934 posted

    Rather than go down that rabbit hole and post the source for the custom middleware which references other code files I've written I just switched it back to the default out of the box implementation:

    app.UseAuthentication();

    However it doesn't resolve the issue. So then I decided I'd create a new project to see if I could reproduce this with the following startup but yet it works as I want it to using the path as "/signIn" instead of "/Home/SignIn", weird.

        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(
                        Configuration.GetConnectionString("DefaultConnection")));
                services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
                    .AddEntityFrameworkStores<ApplicationDbContext>();
    
                services.ConfigureApplicationCookie(options =>
                {
                    options.LoginPath = "/signin";
                });
    
                services.AddControllersWithViews();
                services.AddRazorPages();
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                    app.UseDatabaseErrorPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/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.UseRouting();
    
                app.UseAuthentication();
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Home}/{action=Index}/{id?}");
                    endpoints.MapRazorPages();
                });
            }
        }

    Thursday, March 11, 2021 4:25 AM