6

I am attempting to change my start page in my ASP.NET Core MVC C# app. I want to first take the user to a login page and I have changed in the Startup.cs to this:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseEndpoints(endpoints =>
    {
       endpoints.MapControllerRoute(
         name: "default",
         pattern: "{controller=Login}/{action=Index}/{id?}");
    }
}

and my controller looks like this

public class LoginController : Controller
{
  public IActionResult Index()
  {
     return View();
  }
}

And I have a page called Login.cshtml

What am I missing here?

This is my startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using eDrummond.Models;

namespace eDrummond
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddDbContext<eDrummond_MVCContext>();

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(opetions =>
                {
                    options.LoginPath = "/Login/Index";
                });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseAuthentication();

            app.UseCors(
                options => options.AllowAnyOrigin()
            );
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Login}/{action=Index}/{id?}");
            });
        }
    }
}

I am using VS2019 and created an asp.net core app, then selected MVC and all I've done is Scaffold Tables. SO the config should be correct?

Vy Do
  • 46,709
  • 59
  • 215
  • 313
HotTomales
  • 544
  • 2
  • 6
  • 13

2 Answers2

9

You need to take regard of an authentication flow. First you are unauthorized. When you access any page where you aren't authorized you would like to REDIRECT to your login page, right? Then you need to tell this the program:

public void ConfigureServices(IServiceCollection services) {
  services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    // What kind of authentication you use? Here I just assume cookie authentication.
    .AddCookie(options => 
    {
      options.LoginPath = "/Login/Index";
    });
}

public void Configure(IApplicationBuilder app) {
  // Add it but BEFORE app.UseEndpoints(..);
  app.UseAuthentication();
}

Here is a stackoverflow topic, that addresses your problem:

ASP.NET core, change default redirect for unauthorized

Edit:

It turns out, that you can do something like this:

// This method gets called by the runtime. Use this method to add services to the container.

public void ConfigureServices(IServiceCollection services)
{
    // You need to comment this out ..
    // services.AddRazorPages();
    // And need to write this instead:
    services.AddMvc().AddRazorPagesOptions(options =>
    {
        options.Conventions.AddPageRoute("/Login/Index", "");
    });
}

2. Edit:

So my first answer was not wrong, but it it did not included the changes to the controller it would need. There are two solutions:

  1. You add [Authorize] to all controller, you want to be authorized, for example IndexModel (located in /Pages/Index.cshtml.cs) and when entered, the program would see, the user is not authorized and would redirect to /Login/Index (file located in /Pages/Login/Index.cshtml.cs). Then you don't need to specify a DefaultPolicy or a FallbackPolicy (see source code below for FallbackPolicy reference)
  2. You can make the program say, that all controller need to be authorized even when not marked by [Authorize]. But then you need to mark those controller you want pass without authorization with [AllowAnonymous]. This is how it should be implemented then:

Structure:

/Pages
   Index.cshtml
   Index.cshtml.cs
   /Login
      Index.cshtml
      Index.cshtml.cs
/Startup.cs

Files:

// File located in /Startup.cs:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.Configuration;

namespace stackoverflow_aspnetcore_59448960
{
    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)
        {
            // Does automatically collect all routes.
            services.AddRazorPages();

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(options =>
                {
                    // That will point to /Pages/Login.cshtml
                    options.LoginPath = "/Login/Index";
                }); ;

            services.AddAuthorization(options =>
            {
                // This says, that all pages need AUTHORIZATION. But when a controller, 
                // for example the login controller in Login.cshtml.cs, is tagged with
                // [AllowAnonymous] then it is not in need of AUTHORIZATION. :)
                options.FallbackPolicy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
            });
        }

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

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                // Defines default route behaviour.
                endpoints.MapRazorPages();
            });
        }
    }
}

// File located in /Pages/Login/Index.cshtml.cs:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace stackoverflow_aspnetcore_59448960.Pages.Login
{
    // Very important
    [AllowAnonymous]
    // Another fact: The name of this Model, I mean "Index" need to be
    // the same as the filename without extensions: Index[Model] == Index[.cshtml.cs]
    public class IndexModel : PageModel
    {
        private readonly ILogger<IndexModel> _logger;

        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {

        }
    }
}

// File located in /Pages/Index.cshtml.cs

using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace stackoverflow_aspnetcore_59448960.Pages
{
    // No [Authorize] needed, because of FallbackPolicy (see Startup.cs)
    public class IndexModel : PageModel
    {
        private readonly ILogger<IndexModel> _logger;

        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {

        }
    }
}
Teneko
  • 1,417
  • 9
  • 16
  • I add in your code per your post but when I launch my app, it still takes me to the page of index.cshtml. I am using .NET Core 3.1 – HotTomales Dec 23 '19 at 00:16
  • Can you please add the code of your LoginController here? – Teneko Dec 23 '19 at 00:21
  • Ohh I thought... You aren't using cshtml files? These files are called Razor Pages. – Teneko Dec 23 '19 at 00:36
  • When I launch my app from Visual Studio 2019, I am taken to localhost:44336 and it shows \Views\Home\Index.cshtml - still not showing my \Views\Login\Index.cshtml – HotTomales Dec 23 '19 at 00:37
  • oh, I thought Razor pages were something different. I am using .cshtml pages. My mistake. – HotTomales Dec 23 '19 at 00:37
2

You should have folder structure as shown below.

Views
   Login
      Index.cshtml

It should take you to login page by default.

Venkata Dorisala
  • 4,783
  • 7
  • 49
  • 90
  • Ah - maybe that is my issue. My folder structure is like this \Views\Home\index.cshtml .... \Views\Home\Login.cshtml ..... \Views\Home\Privacy.cshtml – HotTomales Dec 23 '19 at 00:21
  • Okay - so I mirrored your directory structure and still giving me the page at \Views\Home\index.cshtml – HotTomales Dec 23 '19 at 00:24
  • I created a new project and tried with your endpoint configuration. It took me straight into login page. I don't see any other cause for your issue. See if you are missing something else which isn't given to us in your question. – Venkata Dorisala Dec 23 '19 at 00:27
  • see my edit. I updated OP to include my entire startup.cs file. IDK why things aren't working :( – HotTomales Dec 23 '19 at 00:31
  • just do a clean, build and then run it. I don't think there is any issue in your setup. – Venkata Dorisala Dec 23 '19 at 00:39