Search code examples
asp.net-mvcasp.net-core-mvcasp.net-identity-3

ASP.NET MVC 6 custom user identity, persisting the logged-in user for a long time?


So I have ASP.NET MVC 6 + AngularJS application with custom user identity (not using EF) which authenticates the user against different db without EF, etc.

I have a couple of custom implementations of some interfaces needed for the user identity to work.

  • IUserStore<MyUser>, IUserPasswordStore<MyUser> - only a couple of methods are implemented for getting the user with my custom code. Nothing interesting there.

  • IPasswordHasher<MyUser> implementation for validating the hashed password using my own code for decrypting the password, etc.

  • IUserClaimsPrincipalFactory<MyUser> implementation for creating the ClaimsPrincipal object containing some custom claims for my own purposes.

In the AccountControler for signing in and logging off I am using this:

SignInManager.PasswordSignInAsync(username, password, true, shouldLockout: false)
SignInManager.SignOut();

where the SignInManager is my custom one - SignInManager<MyUser>.

So far everything is straight forward.

Now in the Startup.cs I have:

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.TryAdd(ServiceDescriptor.Scoped<IUserStore<MyUser>, ApplicationUserStore>());
    services.TryAdd(ServiceDescriptor.Scoped<IUserPasswordStore<MyUser>, ApplicationUserStore>());
    services.TryAdd(ServiceDescriptor.Scoped<IPasswordHasher<MyUser>, ApplicationSitePasswordHasher>());
    services.TryAdd(ServiceDescriptor.Scoped<IUserClaimsPrincipalFactory<MyUser>, MyUserClaimsPrincipalFactory>());

    services.AddIdentity<MyUser, MyUserRole>();

    services.ConfigureIdentity(options =>
    {
        options.Password.RequireDigit = false;
        options.Password.RequireLowercase = false;
        options.Password.RequireNonLetterOrDigit = false;
        options.Password.RequireUppercase = false;
        options.Password.RequiredLength = 1;

        options.User.RequireUniqueEmail = false;
        options.User.UserNameValidationRegex = string.Empty;
    });

    services.ConfigureIdentityApplicationCookie(options =>
    {
        options.SlidingExpiration = true;
        options.ExpireTimeSpan = TimeSpan.FromDays(30);
        options.AuthenticationScheme = IdentityOptions.ApplicationCookieAuthenticationScheme;
        options.AutomaticAuthentication = true;
        options.LoginPath = PathString.Empty; 
    });

    ...

}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
     ...

     app.UseIdentity();

     ...

     app.UseMvc(routes => .... )
}

And I also have custom authorization attribute dealing when the user gets 401 in the angular http async call. The idea is something like that:

public class MyAuthorize : ActionFilterAttribute
{
    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        bool isAuth = bool isAuth = context.HttpContext.User.Identity.IsAuthenticated;

        bool isFromClient = ...
        string loginPath = ...

        if (!isAuth && isFromClient)
        {
            ...
        }
        else if (!isAuth && !isFromClient)
        {
            context.HttpContext.Response.Redirect(loginPath);
        }
        else
        {
            await next();
        }
    }
}

The question : Even though I have my cookie to expire after 30 days (in that case) I still get unauthenticated (The context.HttpContext.User.Identity.IsAuthenticated property is false) after some period of time and get redirected to the login page due to my logic in the MyAuthorize attribute.

The idle time-out in the IIS pool is 0 as well.

How to make my custom user identity to persist the authenticated user for a really long time?


Solution

  • Does "some period of time" is about "30 minutes since login"? :)

    Implement IUserSecurityStampStore<User> interface.

    Long description is in ASP.NET 5 Identity 3 users get signed out after some time