How to prevent multiple & concurrent login in .Net

2019-08-21 08:10发布

问题:

I'm trying to limit user login in a web application. Some sources [1] & [2] use same idea by using await _userManager.UpdateSecurityStampAsync (loginUser);

This is the complete code of Login action in AccountController:

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Login (LoginViewModel model, string returnUrl = null) {
        ViewData["ReturnUrl"] = returnUrl;
        if ( ModelState.IsValid ) {

            var loginUser = await _userManager.FindByEmailAsync(model.Email);
            if ( loginUser == null ) {
                ModelState.AddModelError (string.Empty, "Invalid username/password.");
                return View ();
            }

            await _userManager.UpdateSecurityStampAsync (loginUser);
            var result = await _signInManager.PasswordSignInAsync(loginUser, model.Password, isPersistent: false, lockoutOnFailure: true);

            if ( result.Succeeded ) {
                _logger.LogInformation ("User logged in.");
                return RedirectToLocal (returnUrl);
            }
            if ( result.RequiresTwoFactor ) {
                return RedirectToAction (nameof (LoginWith2fa), new { returnUrl, model.RememberMe });
            }
            if ( result.IsLockedOut ) {
                _logger.LogWarning ("User account locked out.");
                return RedirectToAction (nameof (Lockout));
            } else {
                ModelState.AddModelError (string.Empty, "Invalid login attempt.");
                return View (model);
            }
        }

        // If we got this far, something failed, redisplay form
        return View (model);
    }

Above login action looks so familiar. It's just modified by adding UpdateSecurityStampAsync for updating the 'concurrencyStamp' and 'SecurityStamp' columns in the table (dbo.AspNetUsers) everytime user login before PasswordSignInAsync.

I tried to screen shoot from 2 different browser (1st & 2nd attempt from chrome; 3rd & 4th attempt from firefox) with same login. 2nd & 4th was captured after execute UpdateSecurityStampAsync. 2nd & 3rd had same ConcurrencyStamp and SecurityStamp.

I also modified start.cs in ConfigureServices method:

        services.Configure<SecurityStampValidatorOptions> (option =>
            option.ValidationInterval = TimeSpan.FromSeconds (0)
        );

        services.AddAuthentication ()
            .Services.ConfigureApplicationCookie (options => {
                options.SlidingExpiration = true;
                options.ExpireTimeSpan = TimeSpan.FromMinutes (30);
        });

But, after I modified those code above, I still can login, concurrently, from other web browser. I also can login from other machine successfully by using same user name & password.

  1. well, do I miss something ?
  2. Or, UpdateSecurityStampAsync cant be used to prevent users login concurrently ?
  3. Or, .Net Core can't handle this scenario and need 3rd party for user user login management ?

Any help help/suggestion is highly appreciate.