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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With