Exception "System.Security.Cryptography.CryptographicException" after Publishing project - jwt

Everytime I publish my Blazor Server-project to my website domain, and opening the website, this exception occurs, and there's little to no help Googling it:
And it says AppState.cs: line 21, so here's the codeline for it:
This exception is not happening under debugging localhost. When I delete localStorage from the browser on my website, and refreshing, then everything works. But I don't want my customers having this exception and having to tell them to delete the localstorage everytime I'm publishing.
My Program.cs if necessary:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor().AddCircuitOptions(options => options.DetailedErrors = true);
builder.Services.AddHttpClient();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters.ValidateIssuerSigningKey = true; // Validér secret key for JWT
options.TokenValidationParameters.ValidateLifetime = false; // Validér ikke Lifetime på JWT
options.TokenValidationParameters.ValidateAudience = false; // Ikke validér clients(audience), fx BlazorWeb, der skal anvende IdentityServer
options.TokenValidationParameters.ValidateIssuer = false; // Ikke validér IdentityServer(issuer)
options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Secret"])); // Sæt secret key for JWT, der bruges som adgangskode til at tilgå JWT
});
builder.Services.AddScoped<AuthService>();
builder.Services.AddScoped<AuthenticationStateProvider, AppState>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
RewriteOptions options = new RewriteOptions();
options.AddRedirectToWww();
options.AddRedirectToHttps();
app.UseRewriter(options);
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();

After many hours of research, I managed to fix it. I did the following; Added builder.Services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(#"c:\your\path\to\store\keys"));.

Try to set Load User Profile to true in your IIS app pool in the advanced settings.
see this answer, I hope that will help you!

Related

How do you modify the client and api scopes that are predefined in IdentityServer 7 when creating a web app with individual accounts?

I have been stuck on this problem for a few days now. I have a web application being built on .NET Core 7, IdentityServer 7, EntityFramework 7, and Angular 15 and written in C#. The scope in the JWT contains a scope of (MyAppAPI, openid, and profile). I am trying to find a way to add roles to the scope. I've tried several approaches, but all of them are directed towards creating new IdentityResources, Clients, and ApiScopes. This approach throws errors because they already exist from IdentityServer 7.
Hoping someone can help. Thanks.
My latest effort consisted of applying option arguments to the builder.Services.AddIdentityServer().AddApiAuthorization<ApplicationUser, ApplicationDbContext>() method in the Program.cs file. But I get an error saying "Can't determine the type for the client type". So I don't know if I'm close to getting this all resolved or am way off track.
Here are the contents of my Program.cs file:
using Duende.IdentityServer.AspNetIdentity;
using Duende.IdentityServer.EntityFramework.Entities;
using Duende.IdentityServer.Models;
using AdminPortal.Areas.Identity.Data;
using AdminPortal.Areas.Identity.Models;
using AdminPortal.Framework;
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging.AzureAppServices;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
var builder = WebApplication.CreateBuilder(args);
string envName = string.IsNullOrEmpty(builder.Configuration["configEnvName"]) ? "development" : builder.Configuration["configEnvName"].ToString();
builder.Configuration.AddJsonFile("appsettings.json").AddJsonFile($"appsettings.{envName}.json");
builder.Logging.AddAzureWebAppDiagnostics();
builder.Services.Configure<AzureFileLoggerOptions>(options =>
{
options.FileName = "AdminPortal-diagnostics-";
options.FileSizeLimit = 50 * 1024;
options.RetainedFileCountLimit = 5;
});
builder.Services.Configure<AzureBlobLoggerOptions>(options =>
{
options.BlobName = "log.txt";
});
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.IdentityResources = Config.IdentityResources;
options.Clients = Config.Clients;
options.ApiScopes = Config.ApiScopes;
})
.AddProfileService<ProfileService>();
builder.Services.AddAuthentication()
.AddIdentityServerJwt();
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
//builder.Services.AddScoped<IClaimsTransformation, ClaimsTransformer>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();
app.MapFallbackToFile("index.html"); ;
app.Run();
And here are the contents of Config.cs:
using Duende.IdentityServer.Models;
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
using System.Collections.Generic;
namespace AdminPortal.Framework
{
public static class Config
{
public static IdentityResourceCollection IdentityResources =>
new IdentityResourceCollection(
new IdentityResource[]
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
//new IdentityResources.Email(), // Can implement later if needed
//new IdentityResources.Phone(), // Can implement later if needed
//new IdentityResources.Address(), // Can implement later if needed
new IdentityResource("roles", "User roles", new List<string> { "role" })
});
public static ApiScopeCollection ApiScopes =>
new ApiScopeCollection(
new ApiScope[]
{
new ApiScope("AdminPortalAPI"),
new ApiScope("openid"),
new ApiScope("profile"),
new ApiScope("roles")
}
);
public static ClientCollection Clients =>
new ClientCollection(
new Client[]
{
new Client
{
ClientId = "AdminPortalAPI",
ClientName = "AdminPortal Credentials Client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
AccessTokenType = AccessTokenType.Jwt,
ClientSecrets = { new Secret("AdminPortal_client_secret".Sha256()) },
AllowedScopes =
{
"AdminPortalAPI"
}
},
new Client
{
ClientId = "AdminPortal",
ClientName = "AdminPortal SPA",
AllowedGrantTypes = GrantTypes.Code,
AccessTokenType = AccessTokenType.Jwt,
RequirePkce = true,
RequireClientSecret = false,
AllowedScopes = { "openid", "profile", "AdminPortalAPI", "roles" },
RedirectUris = { https://localhost:44463/auth-callback },
PostLogoutRedirectUris = { https://localhost:44463/ },
AllowedCorsOrigins = { https://localhost:44463 },
AllowOfflineAccess = true
}
}
);
}
}
I found the solution to my problem. So I'll report it here for anyone else that finds themselves struggling with this issue or similar.
If you create a new project in Visual Studio and tell it to include Individual Accounts, it will use IdentityServer to build out an authentication framework that will make it easy to manage user accounts and authenticate users. However, if you want to implement role-based security, you'll have to build it out manually because the preconfigured code only partially implements IdentityServer and is not designed to let you customize the scopes (reference link: https://github.com/dotnet/aspnetcore/issues/16939).
To resolve this issue, I found a great tutorial that helped me build out the authentication and authorization framework using IdentityServer for my Angular 15 .NET Core 7 web application. Here is the link to it: https://code-maze.com/angular-security-with-asp-net-core-identity/

How do I solve the keycloak refresh /#state on my angular7 project - i'm using keycloak-angular

I have also tried all varying combinations for web origins and valid redirect URIs
I login via keycloak and it continuously redirects me back and forth between my localhost application and this url: http://localhost:4200/#state=166446fd-daf6-4b76-b595-583c01c663df&session_state=57ead1f3-bf41-4117-9ddf-75e37c9248e7&code=8692b58b-0868-4762-b82e-acde9911dd34.57ead1f3-bf41-4117-9ddf-75e37c9248e7.1e8b5b9d-b590-453e-b396-62b46c18cc9f
I have tried it on firefox and chrome but with the same issue - it seems to be looking for the keycloak.json file in the network tab even though I can login to the correct realm via keycloak
GET http://localhost:4200/keycloak.json 404 (Not Found)
scheduleTask # zone.js:2969
ERROR An error happened during Keycloak initialization. core.js:1601
Unhandled Promise rejection: An error happened during Keycloak initialization. ; Zone: ; Task: Promise.then ; Value: An error happened during Keycloak initialization. undefined
static init(): Promise<any> {
const keycloakAuth: any = Keycloak({
url: 'http://localhost:8080/auth',
realm: 'ContractPortal',
clientId: 'secretkey2',
'ssl-required': 'external',
'public-client': true
});
KeycloakService.auth.loggedIn = false;
return new Promise((resolve, reject) => {
keycloakAuth.init({onLoad: 'login-required'})
.success(() => {
console.log(keycloakAuth);
KeycloakService.auth.loggedIn = true;
KeycloakService.auth.authz = keycloakAuth;
KeycloakService.auth.logoutUrl = keycloakAuth.authServerUrl
+ '/realms/angular_keycloak/protocol/openid-connect/logout?redirect_uri='
+ document.baseURI;
resolve();
})
.error(() => {
reject();
});
});
}
it'd be great if one of you guys can point me in the right direction to solve this issue...
I have found another similar question to what I have asked link but not sure how to implement this solution! this is my provider setup -
providers: [
{
provide: APP_INITIALIZER,
useFactory: initializer,
multi: true,
deps: [KeycloakService]
}
],
but OP puts the following in his provider
providers: [
KeyCloakService,
AssetService,
{
provide: LocationStrategy,
useClass: PathLocationStrategy
}
]
Please let me know if you require any other information
For anybody that ran into the same issue - I misunderstood the keycloak.json file and did not know where to get it - so I was exporting the complete json file from keycloak but THIS is not how you should get it!!
First you have to go to your realm > clients and click on installation
then download the keycloak OIDC json file
then place it next to the index.html file in your application
This solved my issue - hope it helps somebody else
I was researching on the internet and it is the same case, for me my angular page is reloading automatically in infnite loop
I did some changes in keycloak-init.ts file (please find following code and change checkLoginIframe from true to false)
Old Code: keycloak.init ({onLoad: 'login-required', "checkLoginIframe": true})
New Code: keycloak.init ({onLoad: 'login-required', "checkLoginIframe": false})
this.loadingService.isLoading$.pipe(delay(100)).subscribe((data => {
this.loading = data
}))
this.isLogging = await this.keycloak.isLoggedIn();
type roleUser = Array<{ id: number, text: string }>
if (this.isLogging) {
this.userProfile = await this.keycloak.loadUserProfile();
this.userRoles = await this.keycloak.getUserRoles();
}else {
// this.clearSession();
}
if you are using "this.keycloak.loadUserProfile()" Remove this "clear session"

Identity Server 3 + ASP.NET Core 2.0 MVC app - Federated single sign-out not including a redirect to ADFS before ending session

My web app is client to an Identity Server 3 STS, which is federated with ADFS for the external IdP. Sign-in works great. Sign-out from the STS is fine. But I have never been able to get IdSrv3 to redirect to ADFS for sign-out prior to ending the IdSrv3 session and ultimately redirecting to the app.
If I understand correctly, I should be able to have ADFS post back to the RP (IdSrv3) after signing out, at which point IdSrv3
Read the docs:
https://identityserver.github.io/Documentation/docsv2/advanced/federated-post-logout-redirect.html
As well as much of the anthology of the GitHub issues surrounding this topic of federated single sign-out.
Tracing through IdSrv3 I never see an attempt to redirect to ADFS for sign-out, so I assume I'm missing configuration here.
Once complexity is that I'm running IdSrv3 however my client apps are ASP.NET Core 2.0 so many of the samples don't cleanly reconcile with the latest Microsoft identity client middleware.
On the IdSrv3, these are (I believe) the relevant configuration components:
Configuration of Additional Identity Providers:
var wsFed = new WsFederationAuthenticationOptions
{
Wtrealm = ConfigurationManager.AppSettings["Wtrealm"],
MetadataAddress = metaDataAddress,
AuthenticationType = "ADFS",
Caption = "ACME ADFS",
SignInAsAuthenticationType = signInAsType
};
The IdSrv3 middleware:
coreApp.UseIdentityServer(
new IdentityServerOptions
{
SiteName = "eFactoryPro Identity Server",
SigningCertificate = Cert.Load(),
Factory = factory,
RequireSsl = true,
AuthenticationOptions = new AuthenticationOptions
{
IdentityProviders = ConfigureAdditionalIdentityProviders,
EnablePostSignOutAutoRedirect = true,
EnableSignOutPrompt = false,
EnableAutoCallbackForFederatedSignout = true
},
LoggingOptions = new LoggingOptions
{
EnableHttpLogging = true,
EnableKatanaLogging = true,
//EnableWebApiDiagnostics = true,
//WebApiDiagnosticsIsVerbose = true
}
});
coreApp.Map("/signoutcallback", cleanup =>
{
cleanup.Run(async ctx =>
{
var state = ctx.Request.Cookies["state"];
await ctx.Environment.RenderLoggedOutViewAsync(state);
});
});
});
Now for the Client side, an ASP.NET Core 2.0 MVC application:
Update: See accepted answer - the redirect to IdP for sign-out should have been handled on the IdSrv3 side with respect to redirecting to the external IdP (ADFS)
public static void ConfigureAuth(this IServiceCollection services,
ITicketStore distributedStore,
Options.AuthenticationOptions authOptions)
{
services.AddDataProtection();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromHours(8);
options.SlidingExpiration = true;
options.SessionStore = distributedStore;
})
.AddOpenIdConnect(options =>
{
options.Authority = authOptions.Authority;
options.ClientId = authOptions.ClientId;
options.ClientSecret = authOptions.ClientSecret;
options.ResponseType = "code id_token";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("roles");
options.Scope.Add("email");
options.Scope.Add("offline_access");
options.RequireHttpsMetadata = false;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.Events = new OpenIdConnectEvents()
{
OnRedirectToIdentityProviderForSignOut = n =>
{
var idTokenHint = n.ProtocolMessage.IdTokenHint;
if (!string.IsNullOrEmpty(idTokenHint))
{
var sessionId = n.HttpContext?.Session?.Id;
var signOutRedirectUrl = n.ProtocolMessage.BuildRedirectUrl();
if (sessionId != null)
{
n.HttpContext.Response.Cookies.Append("state", sessionId);
}
n.HttpContext?.Session?.Clear();
n.Response.Redirect(signOutRedirectUrl);
}
return Task.FromResult(0);
}
};
});
}
From the documentation I should be passing the "sign out message id" into that 'state' cookie. However, this extension method doesn't work in ASP.NET Core 2.0 as we don't really have access to OwinContext anymore.
var signOutMessageId = n.OwinContext.Environment.GetSignOutMessageId();
I've even tried instantiating a new OwinContext(n.HttpContext) to get at the environment dictionary - however, the value that the "GetSignOutMessageId()" obtains has a key of "id" which I can't find in the Owin variables.
It seems this cookie is really just necessary to persist state through all of the redirects so that after the PostLogoutUri of my client application is hit, which is currently set to "https://myapp/signout-callback-oidc", the message id can be used to finish cleaning up the session.
I'm also confused as to what role the "EnableAutoCallbackForFederatedSignout = true" setting plays on the IdSrv3 configuration.
From this description and looking at the code it would apear that this just saves me from having to set the "WReply" parameters on the ADFS signout:
https://github.com/IdentityServer/IdentityServer3/issues/2613
I would expect that ADFS would redirect to:
"https://myIdSrv3/core/signoutcallback" automatically if this settings was 'true'.
If anyone has any guidance to share it is much appreciated.
It turns out I was conflating some of the concepts in IdSrv3 that describe Federated Single Sign-Out initiated by the External Idp as opposed to my use case - sign-out initiated by the IdSrv3 client app, cascading "up" to the external IdP.
The root cause of this problem was in my UserService implementation. There I had overriden the "AuthenticateExternalAsync()" method, but did not specify the external identity provider in the AuthenticateResult object.
Here is the corrected implementation:
public override Task AuthenticateExternalAsync(ExternalAuthenticationContext context)
{
...
context.AuthenticateResult = new AuthenticateResult(
user.Id,
user.UserName,
new List<Claim>(),
context.ExternalIdentity.Provider);
return Task.FromResult(0);
}
Once the External Idp was specified in my AuthenticateResult, I was able to handle the WsFederationAuthenticationNotifications.RedirectToIdentityProvider event.
For the sake of completeness, here is my code to handle federated sign-out (client intiatited) from ADFS vis WsFed. It is more or less straight from the IdSrv3 documentation:
Notifications = new WsFederationAuthenticationNotifications()
{
RedirectToIdentityProvider = n =>
{
if (n.ProtocolMessage.IsSignOutMessage)
{
var signOutMessageId = n.OwinContext.Environment.GetSignOutMessageId();
if (signOutMessageId != null)
{
n.OwinContext.Response.Cookies.Append("state", signOutMessageId);
}
var cleanUpUri =
$#"{n.Request.Scheme}://{n.Request.Host}{n.Request.PathBase}/external-signout-cleanup";
n.ProtocolMessage.Wreply = cleanUpUri;
}
return Task.FromResult(0);
}
}
And finally, my /external-signout-cleanup implementation:
coreApp.Map("/external-signout-cleanup", cleanup =>
{
cleanup.Run(async ctx =>
{
var state = ctx.Request.Cookies["state"];
await ctx.Environment.RenderLoggedOutViewAsync(state);
});
});

Why is IdentityServer redirecting to http rather than https?

I have a very simple MVC5 website that I'm trying to secure with IdentityServer3.
Both my website and my IdentityServer instance are hosted as separate sites in AppHarbor. Both are behind https.
When I hit a resource in my website that is protected by an [Authorize] attribute (e.g., /Home/About), I am successfully redirected to IdentityServer, and I can successfully authenticate.
When IdentityServer POSTs its response back to the website (via app.FormPostResponse.js), the website responds with a 302 redirect to the requested resource - as expected. However, this redirect is to http, not https (see the network trace below).
I'm sure this is just something wrong with my IdentityServer config, but I'd appreciate any pointers as to what I've got wrong.
(AppHarbor uses a reverse proxy (nginx I believe) in front of IIS, where SSL terminates - so I have RequireSsl = false for this scenario, as per the IdentityServer documentation.)
Here is my website's Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://<my-idsrv3>.apphb.com/identity",
ClientId = "<my-client-id>",
Scope = "openid profile roles email",
RedirectUri = "https://<my-website>.apphb.com",
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies",
UseTokenLifetime = false
});
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
}
}
Here is Startup.cs from my IdentityServer3 instance:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/identity", idsrvApp =>
{
idsrvApp.UseIdentityServer(new IdentityServerOptions
{
SiteName = "My Identity Server",
SigningCertificate = Certificates.LoadSigningCertificate(),
RequireSsl = false,
PublicOrigin = "https://<my-idsrv3>.apphb.com",
Factory = new IdentityServerServiceFactory()
.UseInMemoryUsers(Users.Get())
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get())
});
});
}
}
Here is the definition of my website Client:
new Client
{
Enabled = true,
ClientName = "My Website Client",
ClientId = "<my-client-id>",
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
"https://<my-website>.apphb.com"
},
AllowAccessToAllScopes = true
}
Here is the trace from Chrome, after clicking 'Yes, Allow' on the IdentityServer consent screen:
So it looks like this issue was caused by my client website being behind an SSL-terminating nginx front-end.
With reference to this GitHub issue, I added the following to the start of my website's app configuration:
app.Use(async (ctx, next) =>
{
string proto = ctx.Request.Headers.Get("X-Forwarded-Proto");
if (!string.IsNullOrEmpty(proto))
{
ctx.Request.Scheme = proto;
}
await next();
});
This makes the website aware that incoming requests were over https; this in turn appears to ensure that the IdentityServer3 middleware generates https uri's.
Had the same issue running identityserver4 in an Azure App Service. Even with forced https, the generated urls in .well-known/openid-configuration were still http://.
Fixed using the same solution as the other answer, but using AspNetCore ForwardedHeadersExtensions:
var forwardOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
// Needed because of mixing http and https.
RequireHeaderSymmetry = false,
};
// Accept X-Forwarded-* headers from all sources.
forwardOptions.KnownNetworks.Clear();
forwardOptions.KnownProxies.Clear();
app.UseForwardedHeaders(forwardOptions);
See also https://github.com/IdentityServer/IdentityServer4/issues/1331 for more discussion on this subject.
Add forwarded headers in your startup
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
});
and
app.UseForwardedHeaders(new ForwardedHeadersOptions()
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
Finally tell the config it has to replace the http to https in the redirect url. I'm still looking for a better way to implement this.
in your .addopenidconnect() add:
Func<RedirectContext, Task> redirectToIdentityProvider = (ctx) =>
{
if (!ctx.ProtocolMessage.RedirectUri.StartsWith("https") && !ctx.ProtocolMessage.RedirectUri.Contains("localhost"))
ctx.ProtocolMessage.RedirectUri = ctx.ProtocolMessage.RedirectUri.Replace("http", "https");
return Task.FromResult(0);
};
opt.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = redirectToIdentityProvider
};

ASP.NET Core Authorize Redirection to wrong URL

I am trying to run a web application with the following route mapped:
app.UseMvc(routes =>
{
routes.MapRoute(
"default",
"WoL/{controller=Account}/{action=Login}/{id?}");
});
If the user is not authenticated and tries to access a action having the AuthorizeAttribute, the user should be redirected to the default login URL (as seen above). But the user gets redirected to "/Account/Login" instead of "/WoL/Account/Login". How can I redirect the user to "/WoL/Account/Login", if the user is not authenticated? I have configured the following Cookie Authentication:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
LoginPath = new PathString("/WoL/Account/Login"),
AutomaticChallenge = true
});
The answer of #Dmitry is not working anymore in ASP.NET Core 3.1. Based on the documentation that you can find here, you have to add the following code to the ConfigureServices:
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Latest)
.AddRazorPagesOptions(options =>
{
options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
options.Conventions.AuthorizeAreaPage("Identity", "/Account/Logout");
});
services.ConfigureApplicationCookie(options =>
{
options.LoginPath = $"/Identity/Account/Login";
options.LogoutPath = $"/Identity/Account/Logout";
options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});
This works for me (in Startup.ConfigureServices):
services.AddIdentity<User, UserRole>(options =>
{
options.Cookies.ApplicationCookie.LoginPath = new PathString("/Admin/Account/Login");
});
Try to add options.ForwardChallenge = "oidc"; to AddCookie options config