Critical Developers

Programmers Knowledge Base

Redirect to Login Page if Session variable not exist in ASP.Net Core

In this article, we will learn how to check if session variable is exist and redirect to login page if session expires.

We can achieve this using middleware, so I will explain you with 2 methods:-

1) Using only Middleware (Simplest Method)

2) Using Policy and Middleware

Method-1: Using Middleware (Simplest Method)

Here we will add a small code in middleware in Startup.cs and the work done. It will check if session value is null or not and redirect to login page. See below code in bold-

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {

//... Other Middlewares

            app.UseSession();
            app.Use(async (context, next) =>
            {
                string CurrentUserIDSession= context.Session.GetString("CurrentUserID");
                if (!context.Request.Path.Value.Contains("/Account/Login"))
                {
                    if (string.IsNullOrEmpty(CurrentUserIDSession))
                    {
                        var path = $"/Account/Login?ReturnUrl={context.Request.Path}";
                        context.Response.Redirect(path);
                        return;
                    }

                }
                await next();
            });

//... Other Middlewares
        }

Note:- Register Session Service in ConfigureServices method of Startup.cs as shown below:-

        public void ConfigureServices(IServiceCollection services)
        {
            //... Other services

            services.AddSession(options =>
            {
                options.Cookie.Name = "_aspnetCoreSession";
                options.IdleTimeout = TimeSpan.FromMinutes(20);
                options.Cookie.IsEssential = true;
            });

            //... Other services
        }

Thats it !!


Method-2: Using Policy and Middleware

The logic behind is, we will create a policy "AuthorizeSessionPolicy" which will check session existence and return Fail and Succeed flag.

Then we will create a custom Middleware which will validate this policy, and if validation fails - HttpContext will redirect to Login Page with ReturnURL.

Note we are using Middleware to check the session globally which means in every request.

So refer below steps with code.

Steps:-

1) Create a Policy

2) Register the Policy in Startup.cs

3) Create a Custom Middleware Class which will check the policy

4) Call above Middleware in Configure method of Startup.cs to get called in every request


// =======================================================================
// Step-1: Create a Policy Class
// =======================================================================
public class AuthorizeWithSessionRequirement: IAuthorizationRequirement {
 public AuthorizeWithSessionRequirement() {

 }
}
public class AuthorizeSession: AuthorizationHandler < AuthorizeWithSessionRequirement > {
 SignInManager < User > _signInManager;
 SessionManager _sessionManager;

 public AuthorizeSession(
  SignInManager < User > signInManager,
  SessionManager sessionManager) {
  _signInManager = signInManager;
  _sessionManager = sessionManager;
 }
 protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
  AuthorizeWithSessionRequirement requirement) {
  string lsUserId = _sessionManager.CurrentUserId;

  if (string.IsNullOrEmpty(lsUserId)) {
   _signInManager.SignOutAsync();
   context.Fail();
  } else {
   context.Succeed(requirement);
  }

  //
  return Task.CompletedTask;
 }
}
// =======================================================================
// Step-2: Register Policy in Startup.cs
// =======================================================================
public void ConfigureServices(IServiceCollection services) {
 services.AddAuthorization(options => {
  options.AddPolicy("AuthorizeSessionPolicy", policy =>
   policy.AddRequirements(new AuthorizeWithSessionRequirement()));
 });
}
// =======================================================================
// Step-3: Create a Custom Middleware Class
// =======================================================================
public class CheckSessionExistMiddleware {
 private readonly RequestDelegate _next;
 public CheckSessionExistMiddleware(RequestDelegate next) {
  _next = next;
 }
 public async Task Invoke(HttpContext context) {
  if (!context.Request.Path.Value.Contains("/Account/Login")) {
   var endPoint = context.Features.Get < IEndpointFeature > () ? .Endpoint; // To get Page
   var authAttr = endPoint ? .Metadata ? .GetMetadata < AuthorizeAttribute > (); //To get Authorize attribute of page
   // To check if page has authorize attribute with policy as "PolicyName"
   if (authAttr != null && authAttr.Policy == "AuthorizeSessionPolicy") {
    var authService = context.RequestServices.GetRequiredService < IAuthorizationService > ();
    var result = await authService.AuthorizeAsync(context.User, context.GetRouteData(), authAttr.Policy);
    if (!result.Succeeded) {
     var path = $ "/Account/Login?ReturnUrl={context.Request.Path}";
     context.Response.Redirect(path);
     return;
    }
   }
  }
  await _next.Invoke(context);
 }
}

public static class CheckSessionExistMiddlewareExtensions {
 public static IApplicationBuilder UseCheckSessionExistMiddleware(this IApplicationBuilder builder) {
  return builder.UseMiddleware < CheckSessionExistMiddleware > ();
 }
}
// =======================================================================
// Step-4: Call above Middleware in Configure method of Startup.cs
// =======================================================================
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
 // ... Other Middlewares
 app.UseHttpsRedirection();
 app.UseStaticFiles();
 app.UseRouting();
 app.UseSession();
 app.UseAuthentication();
 app.UseCheckSessionExistMiddleware();
 app.UseAuthorization();
 // ... Other Middlewares
}
// SessionManager Class
//================================================================
public class SessionManager
    {
        private readonly ISession _session;
        public const string SessionKeyUserId = "_UserId";
        public SessionManager(IHttpContextAccessor httpContextAccessor)
        {
            _session = httpContextAccessor.HttpContext.Session;
        }

        public void ClearSession()
        {
            // Clear all session. FYI - there is no Abandon method like ASP.Net WebForm
            _session.Clear();
        }
        public string CurrentUserId
        {
            get
            {
                return _session.GetString(SessionKeyUserId) == null ? null : _session.GetString(SessionKeyUserId);
            }
            set
            {
                _session.SetString(SessionKeyUserId, value);
            }
        }
    }
Thats it !!

Globally Encrypt Decrypt Query string in ASP.Net core using Middleware

Like HttpModule in ASP.Net Webform we have Middleware in ASP.Net Core.

So lets create a custom middleware which will encrypt/ decrypt querystring globally.

With this approach, Just take care of TempData because we are redirecting a request twice here so would recommend if you are using tempdata use its Keep Method to preserve it on your RazorPage. Lets start-

Step-1: Create a custom middleware

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyDemos.CustomMiddlewares
{
    // Ref-https://docs.microsoft.com/en-us/aspnet/core/migration/http-modules?view=aspnetcore-3.1
    public class EncryptDecryptQueryStringsMiddleware
    {
        private const string PARAMETER_NAME = "_enc";
        private const string ENCRYPTION_KEY = "key";
        private static ASCIIEncoding encoding;
        private static IHttpContextAccessor _httpContextAccessor;
        private readonly IDataProtector _protector;
        private readonly RequestDelegate _next;
        public EncryptDecryptQueryStringsMiddleware(IHttpContextAccessor httpContextAccessor, IDataProtectionProvider provider, RequestDelegate next)
        {
            encoding = new ASCIIEncoding();
            _httpContextAccessor = httpContextAccessor;
            _protector = provider.CreateProtector
("YOURSECRETKEY");
            _next = next;
        }
        public async Task Invoke(HttpContext context)
        {
            if (UriHelper.GetEncodedUrl(context.Request).Contains("?"))
            {
                string contextQuery = GetAbsoluteUri().Query.ToString();
                //
                if (contextQuery.Contains(PARAMETER_NAME))
                {
                    var enc = context.Request.Query[PARAMETER_NAME];
                    enc = _protector.Unprotect(enc);
                    QueryString queryString = new QueryString(enc);
                    context.Request.QueryString = queryString;
                }
                else if (context.Request.Method == "GET")
                {
                    if (contextQuery != "")
                    {
                        string encryptedQuery = _protector.Protect(contextQuery);
                        string redirectToPagePath = context.Request.Path.Value + "?" + PARAMETER_NAME + "=" + encryptedQuery;
                        context.Response.Redirect(redirectToPagePath);
                    }
                }
            }
            await _next.Invoke(context);
        }
        #region Utils
        private static Uri GetAbsoluteUri()
        {
            var request = _httpContextAccessor.HttpContext.Request;
            UriBuilder uriBuilder = new UriBuilder();
            uriBuilder.Scheme = request.Scheme;
            uriBuilder.Host = request.Host.Host;
            uriBuilder.Path = request.Path.ToString();
            uriBuilder.Query = request.QueryString.ToString();
            return uriBuilder.Uri;
        }

        #endregion
    }
    public static class QueryStringMiddlewareExtensions
    {
        public static IApplicationBuilder UseEncryptDecryptQueryStringsMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<EncryptDecryptQueryStringsMiddleware>();
        }
    }
}

Step-2: Use/Inject middleware in Startup.cs

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                //app.UseStatusCodePagesWithRedirects("/Error/{0}");
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            //
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseEncryptDecryptQueryStringsMiddleware();
            //
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
            });
        }
Thats it !!