Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Session id always changing for ASP.NET Core + Redis + nginx

The sample project https://github.com/xingyu217/Redis-nginx-aspnetcore-session nginx.config:

upstream study_server{
        server localhost:8011 weight=1;
        server localhost:8013 weight=1;
    #server localhost:8014 weight=1;
    #server 172.17.16.147:8012 weight=2;
    #server 172.17.16.147:8011 weight=2;
    }
    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            #root   html;
            #index  index.html index.htm;
        proxy_pass http://study_server/;
            proxy_cookie_path ~*^/.* /;
        proxy_redirect off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }

Get session id: ViewBag.seId= HttpContext.Session.Id;

Startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            //services.AddDistributedMemoryCache();

            services.AddDistributedRedisCache(options =>
            {
                options.Configuration = Configuration.GetConnectionString("RedisConnection");
                options.InstanceName = "master";
            });
            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromSeconds(100);
                //options.Cookie.HttpOnly = true;
            });
            //services.AddSession();
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            //app.UseDeveloperExceptionPage();
            //app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseSession();
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }

Access URL: localhost and refresh again and again, the session id will be always changing.

I checked keys in redis server, it always generate the new key when refresh page. (e.g.masterdef69307-fbd3-c6ed-91d2-009b2306f902)

If I just use a server (localhost:8011):

upstream study_server{
        server localhost:8011 weight=1;
        #server localhost:8013 weight=1;
    #server localhost:8014 weight=1;
    #server 172.17.16.147:8012 weight=2;
    #server 172.17.16.147:8011 weight=2;
    }

The session id won't be changed.

Anyone know it will be appreciated.

Thanks

like image 797
starian chen-MSFT Avatar asked Jan 07 '20 13:01

starian chen-MSFT


People also ask

Why use Redis for distributed user sessions in ASP NET Core?

Episode 16: Using Redis for Distributed User Sessions in ASP.NET Core | ASP.NET session storage is useful for storing state across page views. In single server situations it’s simple to set up because ASP.NET supports in-memory s... | Request Metrics

What is sessionid in ASP NET?

This session has unique ID by which it is uniquely identify a browser with the help of session data on the server. This SessionID value is randomly generated value by the ASP.NET and will be stored in session cookie in the browser only which is non-expiring.

How to generate a new sessionid with each request?

So basically, unless you access your session object on the backend, a new sessionId will be generated with each request This code must be added on the file Global.asax. It adds an entry to the Session object so you fix the session until it expires. protected void Session_Start (Object sender, EventArgs e) { Session ["init"] = 0; }

Why do I get a new session ID every page request?

This is the reason. When using cookie-based session state, ASP.NET does not allocate storage for session data until the Session object is used. As a result, a new session ID is generated for each page request until the session object is accessed.


2 Answers

I actually cannot reproduce the problem on a mac with the configuration (2 local servers load balanced via nginx and connected to the same local redis distributed cache)

Anyways, if applicable, have you tried enabled ip_hash in nginx upstream module ?

From the sessions persistance section in nginx doc:

If there is the need to tie a client to a particular application server — in other words, make the client’s session “sticky” or “persistent” in terms of always trying to select a particular server — the ip-hash load balancing mechanism can be used.

upstream study_server{
    ip_hash;
    server localhost:8011 weight=1;
    server localhost:8013 weight=1;
    #server localhost:8014 weight=1;
    #server 172.17.16.147:8012 weight=2;
    #server 172.17.16.147:8011 weight=2;
}

If that's not solving your issue please have a look at similar issues on stack exchange:

  • https://serverfault.com/questions/133500/nginx-sticky-session-and-iis

  • ASP.NET: Session.SessionID changes between requests

like image 197
Gomino Avatar answered Sep 20 '22 16:09

Gomino


If the CheckConsentNeeded property is assigned with true, the application will not set any non-essential cookie without user consent. This includes the session cookie, which is non-essential by default.

There are at least three solutions to your problem:

  1. You can set CheckConsentNeeded to false.
    ...

    options.CheckConsentNeeded = context => false;

    ...

This will disable the whole cookie consent feature.

  1. You can mark the session cookie as essential.
    ...

    services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromSeconds(100);
        options.Cookie.IsEssential = true;
    });

    ...

This will allow the application to set the session cookie regardless of user's consent.

  1. You can leave everything as it is now. In this case the session will start only after the user clicks the "Accept" button on the cookie use policy popup.
like image 35
Ivan Tsirulev Avatar answered Sep 19 '22 16:09

Ivan Tsirulev