10

I am using a custom authentication for ASP.NET MVC Core which does not use Identity. This is Startup.cs:

public class Startup
{
    public IConfiguration Configuration { get; set; }

    // Configure IoC container
    // https://docs.asp.net/en/latest/fundamentals/dependency-injection.html
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<AppSettings>(options => Configuration.GetSection(nameof(AppSettings)).Bind(options));

        // https://docs.asp.net/en/latest/security/anti-request-forgery.html
        services.AddAntiforgery(options => options.CookieName = options.HeaderName = "X-XSRF-TOKEN");

        services.AddDbContext<DbSesamContext>(options =>
        {
            options.UseSqlServer(Configuration.GetConnectionString("SesamConnection"));
        });

        services.AddDbContext<TerminalDbContext>(options =>
        {
            options.UseSqlServer(Configuration.GetConnectionString("TerminalConnection"));
        });

        services.AddMvcCore()
            .AddAuthorization()
            .AddViews()
            .AddRazorViewEngine()
            .AddJsonFormatters();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory factory)
    {
        // Configure logging
        // https://docs.asp.net/en/latest/fundamentals/logging.html
        factory.AddConsole(Configuration.GetSection("Logging"));
        factory.AddDebug();

        // Serve static files
        // https://docs.asp.net/en/latest/fundamentals/static-files.html
        app.UseStaticFiles();

        // Enable external authentication provider(s)
        // https://docs.asp.net/en/latest/security/authentication/sociallogins.html
        //app.UseIdentity();

        app.UseCookieAuthentication(new CookieAuthenticationOptions()
        {
            AuthenticationScheme = "ResWebAuth",
            LoginPath = new PathString("/login"),
            AccessDeniedPath = new PathString("/unauthorized/"),
            AutomaticAuthenticate = true,
            AutomaticChallenge = true,
        });

        // Configure ASP.NET MVC
        // https://docs.asp.net/en/latest/mvc/index.html
        app.UseMvc(routes =>
        {
            routes.MapRoute("default", "{*url}", new { controller = "Home", action = "Index" });
        });
    }

    public static void Main()
    {
        var cwd = Directory.GetCurrentDirectory();
        var web = Path.GetFileName(cwd) == "server" ? "../public" : "public";

        var host = new WebHostBuilder()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseWebRoot(web)
            .UseKestrel()
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        host.Run();
    }
}

and in my controller:

[Authorize]
public class HomeController : Controller
{
    public async Task<IActionResult> Index()
    {
        ...

        return View();
    }

    [HttpGet("login")]
    [AllowAnonymous]
    public async Task<IActionResult> Login(string ReturnUrl)
    {
        ...

        return View();
    }

    [HttpPost("login")]
    [AllowAnonymous]
    public async Task<IActionResult> Login(LoginInfo loginInfo)
    {
        if (LoginUser(loginInfo.Username, loginInfo.Password))
        {
            var claims = new List<Claim>
                {
                    new Claim(ClaimTypes.Name, loginInfo.Username),
                    new Claim("DbVersion", loginInfo.Terminal.SesamDbVersion),
                    new Claim("DbUrl", loginInfo.Terminal.SesamDbUrl),
                    new Claim("DbName", loginInfo.Terminal.SesamDbName),
                    new Claim("DbUsername", loginInfo.Terminal.SesamDbUserName),
                    new Claim("DbPasswordHash", loginInfo.Terminal.SesamDbPasswordHash),
                };

            var userIdentity = new ClaimsIdentity(claims, "login");

            ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
            await HttpContext.Authentication.SignInAsync("ResWebAuth", principal);

            //Just redirect to our index after logging in. 
            return Redirect("/");
        }
        return View();
    }

    [HttpGet("getchartdata")]
    //[AllowAnonymous]
    public JsonResult GetChartData()
    {
        ...
    }

The log:

info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware[3]
      HttpContext.User merged via AutomaticAuthentication from authenticationScheme: ResWebAuth.
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[1]
      Authorization was successful for user: admin.

...

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/getchartdata/
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed for user: (null).
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
      Executing ChallengeResult with authentication schemes ().
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware[12]
      AuthenticationScheme: ResWebAuth was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action Server.Controllers.HomeController.GetChartData (server) in 5.2905ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 10.1037ms 302 

So basically it successfully authorizes the user in the Index() method of the controller but fails to do so in the GetChartData() method of the same controller.

There seems to be a difference between Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[1] and Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] and I do not understand what it is and how to fix it.

11
  • Why are you not using AddMvc and instead calling AddMvcCore? The following calls do what AddMvc does so there is no reason to use AddMvcCore here Commented Jul 19, 2017 at 18:26
  • This was there by default from the boilerplate that I used. Commented Jul 19, 2017 at 18:28
  • Can you post the full startup class without the constructor? Commented Jul 19, 2017 at 18:31
  • Posted the full startup class without the constructor. Commented Jul 19, 2017 at 18:37
  • Try using AddMvc instead, that could solve the issue (see here) Commented Jul 19, 2017 at 18:44

1 Answer 1

12

For ASP.Net Core 2.0, I added: app.UseAuthentication(); in Startup.Configure() and that resolved this error for me.

Reference: Auth 2.0 Migration announcement

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseStaticFiles();

    app.UseAuthentication();

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

Note: be sure to call UseAuthentication() before calling UseMvc() in Startup.Configure() as noted in the comments.

The order that middleware components are added in the Configure method defines the order in which they're invoked on requests, and the reverse order for the response. This ordering is critical for security, performance, and functionality.

Source ASP.NET Core Docs -> Middleware -> Ordering

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. For me, I was using app.UseAuthentication(); at the last of method. I moved that line to the top of method body and it worked

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.