mhenrickson
mhenrickson

Reputation: 656

.NET Identity and SecurityStampValidator Keeps Logging me Out

I have a .NET 4.5 application with custom Identity implemented. I log in with my user, and then at some point later on, the application makes me log in again. I have verified that the auth cookie is still alive and not expired. After doing much research, it appears that the SecurityStampValidator is expiring which invalidates my user and forces another login. I have tried numerous changes, but nothing works.

Ideally, what I am looking for is to only use the auth cookie expiration, and completely disable the SecurityStampValidator. I have not found a way to do that.

I've created a custom user and user manager:

public class CustomUser : IUser<int>
public class CustomUserManager : UserManager<CustomUser, int>

This is my startup.cs:

public void Configuration(IAppBuilder app)
{
    // create the data access object we are using
    app.CreatePerOwinContext(() => new CustomAccountDataAccess());
    // create the custom user manager
    app.CreatePerOwinContext<CustomUserManager>((opt, cont) => new CustomUserManager(cont.Get<CustomAccountDataAccess>()));
    // create the standard signin manager
    app.CreatePerOwinContext<SignInManager<CustomUser, int>>((opt, cont) =>
            new SignInManager<CustomUser, int>(cont.Get<CustomUserManager>(), cont.Authentication));

    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        // use cookie authentication
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        ExpireTimeSpan = TimeSpan.FromDays(500),
        Provider = new CookieAuthenticationProvider()
        {
            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<CustomUserManager, CustomUser, int>(
                    validateInterval: TimeSpan.FromDays(500),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)),
                    getUserIdCallback: (id) => (id.GetUserId<int>()))
        }
    });
}

If I set validateInterval to some short duration like a minute or two, it works as expected, and my user is logged out after that time. I've set breakpoints in GenerateUserIdentityAsync, and it never gets called. If I set it to some high duration as above, then at some point my user gets logged out anyway. I test this by logging in, and then coming back the next day, and my user is logged out.

I've tried turning off SecurityStampValidator in my CustomUserManager, but that had no effect.

public override bool SupportsUserSecurityStamp => false;

Incidentally, I've loaded the same app code on two different web servers. One server runs .NET 4.5, and the other runs the latest .NET (at least 6.0). The server running .NET 4.5 works exactly as I want. The user is logged in, and stays logged in. On the other server, the user gets logged out as described above.

At this point, I have no idea how to change this so my user stays logged in until the cookie expires. I've seen similar issues posted here, but nothing seems to fix this for me.

Upvotes: 0

Views: 377

Answers (1)

mhenrickson
mhenrickson

Reputation: 656

I finally figured this out. I was running two web apps (one .NET 4.5 MVC, and the other .NET 6.0 Blazor Server), and neither would persist the login. I then came across this ticket: ASP.Net Core Cookie Authentication is not persistant

Which had this comment: "another thought... Is your server storing cookie decryption keys permanently? If not, whenever the server or the app pool restarts, users will have to login again..."

Sure enough, when I tested an application pool cycle, I lost my authentication. It turns out that my .NET 4.5 application was missing machinekey from the web.config. I added that in, and it fixed the issue of losing my auth for that application.

I was also running a Blazor Server App (.NET 6.0). For that one, it does not use machinekey I needed to add DataProtection in the startup.cs:

services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo("C:\storagePathtosavekey"))
    .SetApplicationName("BlazorApp")
    .SetDefaultKeyLifetime(TimeSpan.FromDays(500));

Adding that code fixed auth there. Things seem to be working now, with the auth persisting as I would expect.

Upvotes: 0

Related Questions