I was trying to trace the code execution of eShopOnContainers at runtime, and I stumbled upon this:
public class AccountController : Controller
{
...
[Authorize(AuthenticationSchemes = "OpenIdConnect")]
public async Task<IActionResult> SignIn(string returnUrl)
{
...
}
...
}
I’m not used to seeing this AuthenticationSchemes
parameter on the Authorize
attribute, so I googled for an explanation of what it is. I found this tutorial by Scott Allen: “Experimenting with ASP.NET Core Authentication Schemes”. But it does not point to a code repository which I can download and execute and play with. So I created one.
You can download the code from this GitHub repository. Go to the folder named 2020-09-11-aspnet-authentication-schemes
.
You first need to read Scott Allen’s article before proceeding with the experimentation part below. In case his site is down, I saved a PDF of that article which you can download here.
… finished reading that article?…
Now open the 2020-09-11-aspnet-authentication-schemes/AspNetAuthenticationSchemes.sln
in Visual Studio 2019. You will see an ASP.NET Razor Pages web app.
Look for Page1Model
. It contains this code:
[Authorize]
public class Page1Model : PageModel
{
...
}
It has Authorize
without an AuthenticationSchemes
parameter. That means that the app will use the default authentication scheme configured in our Startup
class — the one named cookie1
, in our case:
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication(options =>
{
options.DefaultScheme = "cookie1";
})
.AddCookie("cookie1", "cookie1", options =>
{
options.Cookie.Name = "cookie1";
options.LoginPath = "/loginc1";
})
.AddCookie("cookie2", "cookie2", options =>
{
options.Cookie.Name = "cookie2";
options.LoginPath = "/loginc2";
});
}
...
}
Now run the app then go to https://localhost:44325/Page1
. It will give you this output:
That page shows that you are now authenticated as Alice-c1
How were you authenticated as Alice-c1
when you did not do anything yet?… That is because this ctx.SignInAsync(...)
line in the case "/loginc1":
part of the code in your Startup
was automatically executed when you visited Page 1.
switch (ctx.Request.Path)
{
case "/loginc1":
var identity1 = new ClaimsIdentity("cookie111");
identity1.AddClaim(new Claim("name", "Alice-c1"));
await ctx.SignInAsync("cookie1", new ClaimsPrincipal(identity1));
break;
...
}
How did Page 1 know that it should execute that code?… It’s because the default authentication scheme has the /loginc1
path in its configuration:
...
options.LoginPath = "/loginc1"
...
Now, to continue with the experiments, try the combination of logging in and logging out using these URLs in your browser:
https://localhost:44325/loginc1
https://localhost:44325/loginc2
https://localhost:44325/logoutc1
https://localhost:44325/logoutc2
Then try to visit
https://localhost:44325/Page1
and
https://localhost:44325/Page2
and
https://localhost:44325/Page3
after each login and logout and see what these pages output on the screen.
Now, logout using https://localhost:44325/logoutc1
.
Then stop the app.
Then comment out the ctx.SignInAsync(...)
for loginc1
in your Startup
class, like this:
case "/loginc1":
var identity1 = new ClaimsIdentity("cookie1");
identity1.AddClaim(new Claim("name", "Alice-c1"));
//await ctx.SignInAsync("cookie1", new ClaimsPrincipal(identity1));
break;
...
Now, when you try visit https://localhost:44325/Page1
, you will get a 302 Found redirect
response with Location: https://localhost:44325/loginc1?ReturnUrl=%2FPage1
.
Interesting…
The string "OpenIdConnect"
in
[Authorize(AuthenticationSchemes = "OpenIdConnect")]
of eShopOnContainers’ WebMVC project is just the name of the authentication scheme to use, the same name used in configuring authentication in the Startup
class:
services.AddAuthentication(...)
.AddOpenIdConnect("OpenIdConnect", options =>
{
...
});
If you navigate to https://localhost:44325/AuthDump
, you will be given this output: