Everything works well on the development local machine (like usual!) but since I release a production version (=Environment Production) with HTTPS support, I am getting the following issue.
First click on login calls my usual login page:
Then if I want to access a feature, the app asks me to login again using the default Asp Net Core Identity login page. What is weird is that I am already logged in as shown on the top right of the page:
It is really not consistent :
Sometimes I can log in right away
Sometimes I have to log in with a second step using the default "Identity" login page (It is like a magic as I don't have such a page in my project!)
When I log out, I get a nullreferenceobject
on the httpcontext
- Maybe this is the clue.
This makes me think httpcontext
is not set properly.
Below is my authentication config from startup.cs
:
#region Cookie options
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = _environment.IsDevelopment()
? CookieSecurePolicy.None : CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Lax;
});
services.ConfigureApplicationCookie(options =>
{
options.AccessDeniedPath = "/Account/AccessDenied";
options.Cookie.Name = "AuthCookie";
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
options.LogoutPath = "/Account/Logout";
options.LoginPath = "/Account/Login";
// ReturnUrlParameter requires
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
options.SlidingExpiration = true;
options.Cookie.SecurePolicy = _environment.IsDevelopment()
? CookieSecurePolicy.None : CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Lax;
options.Cookie.IsEssential = true;
});
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(60);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
#endregion
//This registers the various databases, either as in-memory or via SQL Server (see appsetting.json for connection strings)
var databaseSettings = new DatabaseSettings();
_configuration.GetSection("DatabaseSettings").Bind(databaseSettings);
services.RegisterDatabases(databaseSettings);
#region Identity Services
//https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-configuration?view=aspnetcore-3.1
services.AddDefaultIdentity<ItemUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ExtraAuthorizeDbContext>()
.AddDefaultTokenProviders()
.AddClaimsPrincipalFactory<CustomClaimsPrincipalFactory>();
// Register the Identity services.
services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireDigit = true;
options.Password.RequireUppercase = true;
options.Password.RequiredUniqueChars = 0;
options.Password.RequireLowercase = true;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
options.Lockout.MaxFailedAccessAttempts = 3;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+?!&$€%";
options.User.RequireUniqueEmail = true;
// Default SignIn settings.
options.SignIn.RequireConfirmedEmail = true;
options.SignIn.RequireConfirmedPhoneNumber = false;
});
services.AddScoped<IPasswordHasher<ItemUser>, IpsumPasswordHasher>();
#region Page Authorization
services.AddMvc() //to avoid adding Authorize attribute to all pages model
.AddRazorPagesOptions(options =>
{
options.Conventions.AuthorizeFolder("/");
//Manage folder need to be logged in
options.Conventions.AuthorizeFolder("/Account/Manage");
//Reset password doesn't need to logged in
options.Conventions.AllowAnonymousToPage("/Account/ResetPassword");
//Ask for checking email to validate email address
options.Conventions.AllowAnonymousToPage("/Account/CheckEmail");
//Message when Email has been confirmed
options.Conventions.AllowAnonymousToPage("/Account/ConfirmEmail");
//Authenticated on external login, ask for creating a backup account in the app
options.Conventions.AllowAnonymousToPage("/Account/ExternalLogin");
//Input Email to get a reset password email
options.Conventions.AllowAnonymousToPage("/Account/ForgotPassword");
//Ask for checking email to reset password
options.Conventions.AllowAnonymousToPage("/Account/ForgotPasswordConfirmation");
//User Profile
options.Conventions.AllowAnonymousToPage("/Account/Index");
//Notification that account is lock out
options.Conventions.AllowAnonymousToPage("/Account/Lockout");
//Login screen
options.Conventions.AllowAnonymousToPage("/Account/Login");
//Login when 2FA is enabled = seconde step after standard login
options.Conventions.AllowAnonymousToPage("/Account/LoginWith2fa");
//Login with recovery code = use recovery code if 2FA code not received
options.Conventions.AllowAnonymousToPage("/Account/LoginWithRecoveryCode");
//Notification log out successful
options.Conventions.AllowAnonymousToPage("/Account/Logout");
//Register as a new user
options.Conventions.AllowAnonymousToPage("/Account/Register");
options.Conventions.AllowAnonymousToPage("/Account/ResetPasswordConfirmation");
options.Conventions.AllowAnonymousToPage("/stripewebhook");
});
#endregion
I don't know where to check to fix this. Thanks for any helping.