Base solution for your next web application
Open Closed

Single User Single Session Single Login Control #2922


User avatar
0
tteoh created

Dear Support,

What's the best way to control a single user can only log in a single session at any given time?

[Use Case]

  1. The same user login is used on Chrome and Chrome Incognito are considered two separate session on the same device.
  2. The same user login is used on different browsers on different devices

[Requirements]

  • To detect the user login already has an active session
  • Automatically logout the 1st Session while allowing the 2nd Session to be established

Thanks. /Tommy


13 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    You can use IOnlineClientManager to detect user's online client count, for example

    var onlineClients = _onlineClientManager.GetAllByUserId(new UserIdentifier(TenantId, UserId));
    

    Of course, you can make this check after getting user's id and user's tenant Id. Then you can logout the user if onlineClients.Count > 1 or you can send a signalr message to other clients to log them out and keep last tried user as logged in.

    Thanks.

  • User Avatar
    0
    kythor created

    I would like to implement this solution, but can you please elaborate how to do this?

    Am I correct to add this: var onlineClients = _onlineClientManager.GetAllByUserId(new UserIdentifier(TenantId, UserId));

    into the AccountController method: public virtual async Task<JsonResult> Login(LoginViewModel loginModel, string returnUrl = "", string returnUrlHash = "")

    and how do you "send a signalr message to other clients to log them out and keep last tried user as logged in"?

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @Kythor,

    It is the usage of signalR actually. You can check how we send chat messages to clients of a user in AspNet Zero. You can follow a similar approach to that usage. You just need to exlude currently logged in user.

    Thanks.

  • User Avatar
    0
    tteoh created

    I have few problems here due to the findings:

    1. The count of user logged in reduced after 30 secs logged out. Any explanation for this why it reduced the count after 30 seconds logged out instead of immediately?
    2. The count of user logged in is not increasing when I'm using Postman to log in. What if I want to get the count of user logged in without SignalR integration?
    3. ConnectionId is refreshed when the page is refreshed.

    Thanks. /Tommy

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @tteoh,

    Those are related to SignalR latency I think. We cannot do anything about it. ConnectionId is refreshed when the page is refreshed because a new connection is established.

    Postman uses a different controller (TokenAuthController I think), so you must also handle it in your case.

    Thanks.

  • User Avatar
    0
    tteoh created

    Thank you for the reply, that helped us to have a more understanding about this.

    And we found this article that what we wanted: <a class="postlink" href="http://tech.trailmax.info/2015/09/prevent-multiple-logins-in-asp-net-identity/">http://tech.trailmax.info/2015/09/preve ... -identity/</a> We tried to implement this and we're stuck here:

    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        Provider = new CookieAuthenticationProvider
        {
            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                validateInterval: TimeSpan.FromMinutes(0), // <-- Note the timer is set for zero
                regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
        }
        // other settings
    });
    

    We are getting error:

    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
    

    Can you please guide us how to get the 2 objects (ApplicationUserManager & ApplicationUser) from ABP framework?

    Another problem is when there are 2 pages open from different browsers, one of the browser is not log out when another browser changed the password

    Thanks. /Tommy

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @tteoh,

    ApplicationUserManager -> UserManager and ApplicationUser -> User in AspNet Zero.

    If you want to logout other user when password changes, you should also trigger a signalR event when user changes the password.

    I must say that, this is a hard thing to do.

    Thanks for sharing your experience on this issue.

  • User Avatar
    0
    tteoh created

    Thanks you ismcagdas, that reply helps us to move on!

    The codes below are use to compare the Security Stamps and we are stuck again.

    Default data type is string, which is with 2 type parameters:

    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
        validateInterval: TimeSpan.FromMinutes(0),
        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    

    Since that we are using long data type as User PK, so we implemented this, which is with 3 type parameters:

    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<UserManager, User, long>(
        validateInterval: TimeSpan.FromMinutes(0),
        regenerateIdentityCallback: (manager, user) => (user.GenerateUserIdentityAsync(manager)),
        getUserIdCallback: (user) => (long.Parse(user.GetUserId())))
    

    But it's not working. I've tried with ASP.NET MVC project and it's working.

    And we saw that most of the ASP.NET MVC examples are with these codes:

    app.CreatePerOwinContext(ApplicationDbContext.Create);
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
    app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
    

    So we are wondering is this the reason why our previous code is not working and do we need to implement this? Or it's implemented by ABP framework already?

    Thanks. /Tommy

  • User Avatar
    0
    tteoh created

    <cite>tteoh: </cite> Thanks you ismcagdas, that reply helps us to move on!

    The codes below are use to compare the Security Stamps and we are stuck again.

    Default data type is string, which is with 2 type parameters:

    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
       validateInterval: TimeSpan.FromMinutes(0),
       regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    

    Since that we are using long data type as User PK, so we implemented this, which is with 3 type parameters:

    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<UserManager, User, long>(
       validateInterval: TimeSpan.FromMinutes(0),
       regenerateIdentityCallback: (manager, user) => (user.GenerateUserIdentityAsync(manager)),
       getUserIdCallback: (user) => (long.Parse(user.GetUserId())))
    

    But it's not working. I've tried with ASP.NET MVC project and it's working.

    And we saw that most of the ASP.NET MVC examples are with these codes:

    app.CreatePerOwinContext(ApplicationDbContext.Create);
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
    app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
    

    So we are wondering is this the reason why our previous code is not working and do we need to implement this? Or it's implemented by ABP framework already?

    Thanks. /Tommy

    Dear Support,

    Any further guidance on this issue. We suspect CreatePerOwinContext is critical for cookie validation; especially to get an instance of UserManager; otherwise security stamp in cookie and database cannot be compared.

    Thanks. /Tommy

  • User Avatar
    0
    tteoh created

    This problem is fixed. Please go to the link below to check how is it being fixed.

    [https://github.com/aspnetboilerplate/module-zero/issues/413])

    Hope this might help those people who is trying to do prevent multiple login as well. Feel free to ask me if you have any problem and I will try my best to help.

    Thanks. /Tommy

  • User Avatar
    0
    tteoh created

    This problem is fixed. Please go to the link below to check how is it being fixed.

    [https://github.com/aspnetboilerplate/module-zero/issues/413])

    Hope this might help those people who is trying to do prevent multiple login as well. Feel free to ask me if you have any problem and I will try my best to help.

    Thanks. /Tommy

  • User Avatar
    0
    ismcagdas created
    Support Team

    Thanks for sharing it here @tteoh :)

  • User Avatar
    0
    tteoh created

    <cite>ismcagdas: </cite> Thanks for sharing it here @tteoh :)

    You're welcome :D

    Thanks. /Tommy