问题
I started developing websites using ASP.Net Core 2.2. I'm implementing login/logout by a custom cookie authentication (not Identity).
Please see or clone the repo:
git clone https://github.com/mrmowji/aspcore-custom-cookie-authentication.git .
... or read the following code snippets.
Here is the code in Startup.cs
:
public void ConfigureServices(IServiceCollection services) {
...
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options => {
options.LoginPath = new PathString("/login");
options.ExpireTimeSpan = TimeSpan.FromDays(30);
options.Cookie.Expiration = TimeSpan.FromDays(30);
options.SlidingExpiration = true;
});
...
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
...
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
...
Here is the code of Login
action:
public async Task<IActionResult> Login(LoginViewModel userToLogin) {
var username = "username"; // just to test
var password = "password"; // just to test
if (userToLogin.UserName == username && userToLogin.Password == password) {
var claims = new List<Claim> {
new Claim(ClaimTypes.Name, "admin"),
new Claim(ClaimTypes.Role, "Administrator"),
};
var claimsIdentity = new ClaimsIdentity(
claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties {
AllowRefresh = true,
ExpiresUtc = DateTimeOffset.UtcNow.AddDays(10),
IsPersistent = true,
};
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
authProperties);
...
Cookies are set as expected. I have a .AspNetCore.Cookies
cookie with expiration date of 10 days later. But after about 30 minutes, the user is logged out. How to force the authenticated user to stay logged in, even after the browser is closed?
回答1:
Thanks to @LeonardoSeccia I could find the answer. Please read the comments on the main question.
I just needed to add data protection service inside ConfigureServices
method and provide a way to store/persist the keys (which are used to encrypt/decrypt sensitive data) somewhere, otherwise whenever the server or the app pool restarts, new keys would be generated and old encrypted data (including authentication cookies) will not get decrypted the way they must, which results in a failed authentication. It's necessary if you're deploying to a shared host like me.
If you've used ASP.Net from .Net Framework before, this Data Protection concept is somehow equivalent to MachineKey
.
I've decided to use a file to store the keys.
Here is the final changes in Startup.cs
:
public Startup(IConfiguration configuration, IHostingEnvironment environment) {
Configuration = configuration;
hostingEnvironment = environment;
}
private IHostingEnvironment hostingEnvironment;
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
// create a directory for keys if it doesn't exist
// it'll be created in the root, beside the wwwroot directory
var keysDirectoryName = "Keys";
var keysDirectoryPath = Path.Combine(hostingEnvironment.ContentRootPath, keysDirectoryName);
if (!Directory.Exists(keysDirectoryPath)) {
Directory.CreateDirectory(keysDirectoryPath);
}
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(keysDirectoryPath))
.SetApplicationName("CustomCookieAuthentication");
services.Configure<CookiePolicyOptions>(options =>
{
...
Please check the repo out if you want the whole source code.
来源:https://stackoverflow.com/questions/56490525/asp-net-core-cookie-authentication-is-not-persistant