4

I have an ASP.NET Core site using AspNetCore.Identity.EntityFrameworkCore 1.1.1 and cookies to authorize/authenticate my users. No matter what I choose as my setting in the code below, the cookie expires after about 20 minutes and I can't figure why. The website will then no longer work unless you close the browser and clear the history/cookies. Any ideas?

services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
    //  Require a confirmed email in order to log in
    config.SignIn.RequireConfirmedEmail = true;
})
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

app.UseIdentity();

//  Add cookie middleware to the configure an identity request and persist it to a cookie.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationScheme = "Cookie",
    LoginPath = new PathString("/Account/Login/"),
    AccessDeniedPath = new PathString("/Account/Forbidden/"),
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    ExpireTimeSpan = TimeSpan.FromMinutes(20),
    SlidingExpiration = true,

});

I also have some razor code that controls whether to show the admin menu on the _layout page. This crashes when the cookie expires as the users suddenly has no claims. Is there a better way to handle this?

// If user is admin then show drop down with admin navigation
@if (User.HasClaim(System.Security.Claims.ClaimTypes.Role, "admin"))
{
    <ul class="nav navbar-nav">
        @*etc*@
    </ul>
}
2
  • could you also post your AddIdentity section block? Commented Jun 12, 2017 at 14:59
  • I have updated my question with the AddIdentity block from ConfigureServices. Commented Jun 12, 2017 at 15:08

3 Answers 3

4

You do not need a separate CookieAuthentication middleware when you are using ASPNET identity. UseIdentity() will do that for you and generate a cookie. You can set the "cookie options" in the AddIdentity block of the application like so:

     services.AddIdentity<ApplicationUser, IdentityRole>(config =>
            {
                //  Require a confirmed email in order to log in
                config.SignIn.RequireConfirmedEmail = true;

               // Your Cookie settings
              config.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(1);
              config.Cookies.ApplicationCookie.LoginPath = "/Account/LogIn";
              config.Cookies.ApplicationCookie.LogoutPath = "/Account/LogOut";
            }).AddEntityFrameworkStores<ApplicationDbContext().AddDefaultTokenProviders();

Also, take a look at https://stackoverflow.com/a/34981457/1137785, it gives a background of this sort of a scenario with a very good explanation.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks @Muqeet. Your response helped me to solve my problem!
@muqeetKhan In this new ASP.NET article they are using the following to setup the options. What is the difference in your approach and the article's approach, do you know? // Configure Identity services.Configure<IdentityOptions>(options => {.....}
@nam just different extension methods. In my example, I am using the extension method that takes the options object which is then configured in DI within the method. In the link you gave, they are just doing it separately. Its open source yay! look here on github
Either I am blind, or in 3.1 config.Cookies is gone. How should I configure the LoginPath now?
It's been moved to services.ConfigureApplicationCookie(configure => { ... });
0

I think the problem was that I was persisting data to a cookie with different settings.

Not sure if it's the proper way to do it, but I was able to solve the problem by using both services.AddIdentity and app.UseCookieAuthentication as below.

In ConfigureServices, set the cookie for log in:

        //  set the cookie for sign in
        services.AddIdentity<ApplicationUser, IdentityRole>(config =>
        {               
            //  Require a confirmed email in order to log in
            config.SignIn.RequireConfirmedEmail = true;
            // Cookie settings
            config.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromHours(10);
            config.Cookies.ApplicationCookie.LoginPath = "/Account/LogIn";
            config.Cookies.ApplicationCookie.LogoutPath = "/Account/LogOut";
        }).AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();

In Configure set the cookie scheme used to persist claims:

        //  Add cookie middleware to the configure an identity request and persist it to a cookie.
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationScheme = "Cookie",
            LoginPath = new PathString("/Account/Login/"),
            AccessDeniedPath = new PathString("/Account/Forbidden/"),
            AutomaticAuthenticate = true,
            AutomaticChallenge = true,
            //ExpireTimeSpan = TimeSpan.FromSeconds(10),
            ExpireTimeSpan = TimeSpan.FromHours(10),
            SlidingExpiration = true,
        });

In the log in method, persist the claims:

await HttpContext.Authentication.SignInAsync("Cookie", userPrincipal);

Comments

0

I personally use this way in order to use SignInManager in future:

    builder.Services.AddDbContext<Server04DbContext>(options =>
    {
        options.UseSqlServer(builder.Configuration.GetConnectionString("Local"));
    }).AddIdentity<AppUser, IdentityRole>(options =>
    {
        options.SignIn.RequireConfirmedEmail = false;
        options.User.RequireUniqueEmail = false;
        options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyz0123456789";
        options.Lockout.MaxFailedAccessAttempts = 5;
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
        options.Password.RequireNonAlphanumeric = false;
        options.Password.RequiredLength = 4;
    }).AddDefaultTokenProviders().AddEntityFrameworkStores<Server04DbContext>();

    builder.Services.ConfigureApplicationCookie(options =>
    {
        options.LoginPath = new PathString("/Auth/Login");
        options.LogoutPath = new PathString("/Auth/Logout");
        options.AccessDeniedPath = new PathString("/Home/AccessDenied");

        options.Cookie = new()
        {
            Name = "IdentityCookie",
            HttpOnly = true,
            SameSite = SameSiteMode.Lax,
            SecurePolicy = CookieSecurePolicy.Always
        };
        options.SlidingExpiration = true;
        options.ExpireTimeSpan = TimeSpan.FromDays(30);
    });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.