I'm trying to upgrade my project from .UseMVC (asp.net core 2.2 compat style) to .UseEndpoint Routing and I'm getting re-directed to my suthentication failed page for all my requests. It has to do with the Claims - If I remove the role part of [Authorize(Roles = "Admin")] to simply [Authorize] then it works. It seems that it isn't picking up the claims that are assigned to the user.
It seems to be a very similar issue as https://stackoverflow.com/q/60388730/5683904
Everything worked fine in 2.2, but after migrating to 3.1 and enabling Endpoint Routing, this controller began to refuse requests to any endpoint when [Authorize] attribute is present, When I remove [Authorize] and look at User.Claims, I can see that it does have the required claims (i.e. scope: my-scope, role: MyRole). This happens only if Endpoint Routing is enabled, in case of using UseMvc everything works properly. What's wrong with Authorization in Endpoint Routing mode?
except that I don't even have any custom policies.
Excerpt from Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddAzureAd(options =>
{
Configuration.Bind("AzureAd", options);
AzureAdOptions.Settings = options;
})
.AddAzureAdBearer(options =>
{
Configuration.Bind("AzureAd", options);
AzureAdOptions.Settings = options;
})
.AddCookie(options =>
{
options.ForwardDefaultSelector = context =>
{
//Use Bearer authentication if request contains JWT Bearer token
if (context.Request.Headers.TryGetValue("Authorization", out var value) &&
value.Any(v => v.StartsWith("bearer", StringComparison.OrdinalIgnoreCase)))
{
return "Bearer";
}
return null;
};
options.Events.OnRedirectToLogin = context =>
{
if (context.Request.Headers["Content-Type"].Any(a => a.Contains("application/json")))
{
context.HttpContext.Response.StatusCode = 401;
}
return Task.CompletedTask;
};
});
...
var mvcBuilder = services.AddMvc()
.AddSessionStateTempDataProvider()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});
if (_env.IsDevelopment())
{
mvcBuilder.AddRazorRuntimeCompilation();
}
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromHours(12);
options.Cookie.HttpOnly = true;
});
//Add distributed cache service backed by Sql cache
services.AddDistributedSqlServerCache(o =>
{
o.ConnectionString = sqlConnectionString;
o.SchemaName = "dbo";
o.TableName = "SessionCache";
});
services.ConfigureApplicationCookie(options =>
{
options.ExpireTimeSpan =
TimeSpan.FromHours(12);
options.SlidingExpiration = true;
});
... (rest of Configure services)
}
public void Configure(
...
app.UseSession();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseResponseCompression();
//Add the users Roles as claims to his identity so that it is picked up for authentication purposes
app.Use((context, next) =>
{
var userId = context.User.Identity.Name;
if (userId == null)
{
return next();
}
...
var roles = resourceDataAccess.GetRolesForUser(userId);
if (roles != null)
{
var claims = roles.Select(role => new Claim(ClaimTypes.Role, role.RoleEnum.ToString())).ToList();
var appIdentity = new ClaimsIdentity(claims);
context.User.AddIdentity(appIdentity);
}
return next();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<AppHub>("api/apphub");
endpoints.MapControllerRoute("default", "api/{controller=Account}/{action=SignIn}/{id?}");
endpoints.MapControllerRoute("catch-all", "api/{*url}",
new {controller = "Utility", action = "NotFoundPage"});
});