I have been working on migrating a monolithic ASP Core MVC application to use an service architecture design. The MVC front-end website uses an HttpClient
to load necessary data from the ASP Core Web API. A small portion of the front-end MVC app also requires authentication which is in place using IdentityServer4 (integrated with the back-end API). This all works great, until I put an Authorize
attribute on a controller or method on the Web API. I know I need to somehow pass the user authorization from the front-end to the back-end in order for this to work, but I'm not sure how. I have tried getting the access_token: User.FindFirst("access_token")
but it returns null. I then tried this method and I am able to get the token:
var client = new HttpClient("url.com");
var token = HttpContext.Authentication.GetTokenAsync("access_token")?.Result;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
This method gets the token but still doesn't authentication with the back-end API. I'm pretty new to this OpenId/IdentityServer concepts and any help would be appreciated!
Here is the relevant code from the MVC Client Startup class:
private void ConfigureAuthentication(IApplicationBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = "Cookies",
AutomaticAuthenticate = true,
ExpireTimeSpan = TimeSpan.FromMinutes(60)
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
AuthenticationScheme = "oidc",
SignInScheme = "Cookies",
Authority = "https://localhost:44348/",
RequireHttpsMetadata = false,
ClientId = "clientid",
ClientSecret = "secret",
ResponseType = "code id_token",
Scope = { "openid", "profile" },
GetClaimsFromUserInfoEndpoint = true,
AutomaticChallenge = true, // Required to 302 redirect to login
SaveTokens = true,
TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
NameClaimType = "Name",
RoleClaimType = "Role",
SaveSigninToken = true
},
});
}
and the StartUp class of the API:
// Add authentication
services.AddIdentity<ExtranetUser, IdentityRole>(options =>
{
// Password settings
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequireLowercase = true;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
// User settings
options.User.RequireUniqueEmail = true;
})
.AddDefaultTokenProviders();
services.AddScoped<IUserStore<ExtranetUser>, ExtranetUserStore>();
services.AddScoped<IRoleStore<IdentityRole>, ExtranetRoleStore>();
services.AddSingleton<IAuthorizationHandler, AllRolesRequirement.Handler>();
services.AddSingleton<IAuthorizationHandler, OneRoleRequirement.Handler>();
services.AddSingleton<IAuthorizationHandler, EditQuestionAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, EditExamAuthorizationHandler>();
services.AddAuthorization(options =>
{
/* ... etc .... */
});
var serviceProvider = services.BuildServiceProvider();
var serviceSettings = serviceProvider.GetService<IOptions<ServiceSettings>>().Value;
services.AddIdentityServer() // Configures OAuth/IdentityServer framework
.AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources())
.AddInMemoryClients(IdentityServerConfig.GetClients(serviceSettings))
.AddAspNetIdentity<ExtranetUser>()
.AddTemporarySigningCredential(); // ToDo: Add permanent SigningCredential for IdentityServer
Web API assumes that authentication happens in the host. For web-hosting, the host is IIS, which uses HTTP modules for authentication. You can configure your project to use any of the authentication modules built in to IIS or ASP.NET, or write your own HTTP module to perform custom authentication.
The authentication and authorization mechanism in such a site is simple. After the user logs into the website, a single database holding user information verifies their identity. A session is created on the server, and all subsequent requests use the session to identify the user without another login required.
Added the nuget package here and the following code to fix:
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "https://localhost:44348/",
ApiName = "api"
});
This allows the API to host IdentityServer4 and use itself as authentication. Then in the MvcClient the bearer token can be passed to the API.
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