locked
Re-check authorized user (asp.net core) RRS feed

  • Question

  • User-1417890565 posted

    I’m new in asp.net core razor pages.

    After several days I could implement auhtentication process using my own data base and code.

    My login page checks for user and password and also if a user is active (a flag in my table).

    Let suppose the administrator changes an auhorized user (he is using the system), setting this user to inactive, or even change roles auhtorized. How can I re-check auhorization in the pipeline?

    My code

     public void ConfigureServices(IServiceCollection services)
        {
    ....
          services.AddScoped<IAuthenticateService, AuthenticateService>();
    
          services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
             .AddCookie(options =>
             {
               options.LoginPath = "/Login";
               options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
               options.AccessDeniedPath = "/NotAcess";
             });
    ......
    
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
    ....
          app.UseAuthentication();
          app.UseAuthorization();
    
        // In AuthenticateService (called by login page after checking user existence and password)
        private async Task AuthenticateExecAsync(User user, HttpContext httpContext)
        {
          if (user.Status != User.Status_Active)
            throw new Exception("User inactive");
    
          var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
          identity.AddClaim(new Claim(ClaimTypes.Name, user.Email));
          identity.AddClaim(new Claim(ClaimTypes.GivenName, user.Name));
          List<string> roles = new List<string>();
          foreach (var item in user.userRoles)
            roles.Add(item.Role.RoleId);
          foreach (var role in roles)
            identity.AddClaim(new Claim(ClaimTypes.Role, role));
          var principal = new ClaimsPrincipal(identity);
          await httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);

    tks

    Tuesday, May 26, 2020 1:13 PM

Answers

  • User283571144 posted

    Hi pcintra1,

    As far as I know, if you want to reacting to back-end changes to a specific user, I suggest you could try to create a custom CookieAuthenticationEvents. The ValidateAsync() event can be used to intercept and override validation of the cookie identity.

    I suggest you could add a LastChanged column to  aback-end user database. In order to invalidate a cookie when the database changes you should first, when creating the cookie, add a LastChanged claim containing the current value. Then, when the database changes the LastChanged value should also be updated. If the user has accessed the website, the validate method will check the lastChanged claim data is as same as the database's last changed data. If they are not same, we could call SignOutAsync method to let the user sign out and re-login the whole process.

    About how to add Lastchange claims:

    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, user.Email),
        new Claim("LastChanged", {Database Value})
    };
    
    var claimsIdentity = new ClaimsIdentity(
        claims, 
        CookieAuthenticationDefaults.AuthenticationScheme);
    
    await HttpContext.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme, 
        new ClaimsPrincipal(claimsIdentity));

    Startup.cs configure service:

                services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                   .AddCookie(options =>
                   {
                       options.LoginPath = "/Login";
                       options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
                       options.AccessDeniedPath = "/NotAcess";
                       options.EventsType = typeof(CustomCookieAuthenticationEvents);
    
                   });
                services.AddScoped<CustomCookieAuthenticationEvents>();
    

    The validate method:

    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authentication.Cookies;
    
    public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
    {
        private readonly IUserRepository _userRepository;
    
        public CustomCookieAuthenticationEvents(IUserRepository userRepository)
        {
            // Get the database from registered DI services.
            _userRepository = userRepository;
        }
    
        public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
        {
            var userPrincipal = context.Principal;
    
            // Look for the LastChanged claim.
            var lastChanged = (from c in userPrincipal.Claims
                               where c.Type == "LastChanged"
                               select c.Value).FirstOrDefault();
    
            if (string.IsNullOrEmpty(lastChanged) ||
                !_userRepository.ValidateLastChanged(lastChanged))
            {
                context.RejectPrincipal();
    
                await context.HttpContext.SignOutAsync(
                    CookieAuthenticationDefaults.AuthenticationScheme);
            }
        }
    }

    More details, you could refer to below article.

    https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-3.1#react-to-back-end-changes 

    Best Regards,

    Brando

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, May 27, 2020 9:21 AM

All replies

  • User283571144 posted

    Hi pcintra1,

    As far as I know, if you want to reacting to back-end changes to a specific user, I suggest you could try to create a custom CookieAuthenticationEvents. The ValidateAsync() event can be used to intercept and override validation of the cookie identity.

    I suggest you could add a LastChanged column to  aback-end user database. In order to invalidate a cookie when the database changes you should first, when creating the cookie, add a LastChanged claim containing the current value. Then, when the database changes the LastChanged value should also be updated. If the user has accessed the website, the validate method will check the lastChanged claim data is as same as the database's last changed data. If they are not same, we could call SignOutAsync method to let the user sign out and re-login the whole process.

    About how to add Lastchange claims:

    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, user.Email),
        new Claim("LastChanged", {Database Value})
    };
    
    var claimsIdentity = new ClaimsIdentity(
        claims, 
        CookieAuthenticationDefaults.AuthenticationScheme);
    
    await HttpContext.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme, 
        new ClaimsPrincipal(claimsIdentity));

    Startup.cs configure service:

                services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                   .AddCookie(options =>
                   {
                       options.LoginPath = "/Login";
                       options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
                       options.AccessDeniedPath = "/NotAcess";
                       options.EventsType = typeof(CustomCookieAuthenticationEvents);
    
                   });
                services.AddScoped<CustomCookieAuthenticationEvents>();
    

    The validate method:

    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authentication.Cookies;
    
    public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
    {
        private readonly IUserRepository _userRepository;
    
        public CustomCookieAuthenticationEvents(IUserRepository userRepository)
        {
            // Get the database from registered DI services.
            _userRepository = userRepository;
        }
    
        public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
        {
            var userPrincipal = context.Principal;
    
            // Look for the LastChanged claim.
            var lastChanged = (from c in userPrincipal.Claims
                               where c.Type == "LastChanged"
                               select c.Value).FirstOrDefault();
    
            if (string.IsNullOrEmpty(lastChanged) ||
                !_userRepository.ValidateLastChanged(lastChanged))
            {
                context.RejectPrincipal();
    
                await context.HttpContext.SignOutAsync(
                    CookieAuthenticationDefaults.AuthenticationScheme);
            }
        }
    }

    More details, you could refer to below article.

    https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-3.1#react-to-back-end-changes 

    Best Regards,

    Brando

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, May 27, 2020 9:21 AM
  • User-1417890565 posted

    Thanks a lot Brando, it solved the problem perfectly !

    Best Regards,
    Paulo

    Wednesday, May 27, 2020 5:57 PM