I am using cookies and bearer auth in my application. But i have strange behaviour which I can't explain.
I do have custom middleware where I am adding some required data to Context.Items Its all good but in that middleware User is empty if its bearer but its ok when its cookies.
services
.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(OAuthValidationDefaults.AuthenticationScheme,
CookieAuthenticationDefaults.AuthenticationScheme,
"Identity.Application")
.RequireAuthenticatedUser()
.Build();
});
//CookieAuthenticationDefaults.AuthenticationScheme
services.AddAuthentication()
.AddExternalAuthProviders(Configuration)
.AddFlymarkOpenIdConnectServer()
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.LoginPath = "/Identity/Account/LogIn";
options.SlidingExpiration = true;
options.Events.OnRedirectToLogin = OnRedirectToLogin;
})
.AddOAuthValidation(OAuthValidationDefaults.AuthenticationScheme,
o=>o.Events.OnCreateTicket = OnCreateTicket);
services.ConfigureApplicationCookie(config =>
{
config.Events = new CookieAuthenticationEvents
{
OnRedirectToLogin = OnRedirectToLogin
};
});
Temporary I am using on CreateTicket which solve my problem
private async Task OnCreateTicket(CreateTicketContext arg)
{
if (arg.HttpContext.Items[FlymarkWeb.CurrentUserKey] == null && arg.Identity.IsAuthenticated)
{
var db= (FlymarkContext) arg.HttpContext.RequestServices.GetService(typeof(FlymarkContext));
arg.HttpContext.Items[FlymarkWeb.CurrentUserKey] =
await db.Users.FirstOrDefaultAsync(u => u.Id == arg.Identity.GetUserId());
}
}
And middleware
public async Task Invoke(HttpContext httpContext, FlymarkContext context, DomainService _sourceDomainService)
{
if (httpContext.Items[FlymarkWeb.CurrentUserKey] == null)
{
httpContext.Items[FlymarkWeb.CurrentUserKey] = httpContext.User.Identity.IsAuthenticated
? await context.Users.FirstOrDefaultAsync(u => u.Id == httpContext.User.GetUserId())
: null;
}
....
}
So my question is why cookie and oauth are different? Why if its cookie I can access user in middleware and if its oauth i cant?
That's because ASP.NET Core Identity registers itself as the default authentication scheme handler when you call services.AddIdentity()
.
When receiving a request, the middleware behind app.UseAuthentication()
will automatically call the cookie authentication handler registered by Identity and populate HttpContext.User
with the resulting ClaimsPrincipal
, extracted from the authentication cookie.
With bearer tokens, this doesn't happen because the OAuth validation handler doesn't register itself as the default authentication handler (it's something you have to do manually and explicitly in 2.0).
To configure it as the default handler, you can do that:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = OAuthValidationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OAuthValidationDefaults.AuthenticationScheme;
});
Alternatively, you can directly perform the authentication operation yourself, instead of relying on HttpContext.User
. E.g:
public async Task Invoke(HttpContext httpContext, FlymarkContext context, DomainService _sourceDomainService)
{
if (httpContext.Items[FlymarkWeb.CurrentUserKey] == null)
{
var principal = (await httpContext.AuthenticateAsync(OAuthValidationDefaults.AuthenticationScheme))?.Principal;
httpContext.Items[FlymarkWeb.CurrentUserKey] = principal?.Identity != null && principal.Identity.IsAuthenticated
? await context.Users.FirstOrDefaultAsync(u => u.Id == principal.GetUserId())
: null;
}
}