4

I am adding a custom Disabled column to my AspNetUsers table so that an administrator can temporarily disable an account. (It looks like LockoutEndDateUtc doesn't work exactly as I need.)

But what if an administrator disables an account while the user is logged in? Rather than having to check if the current user account is disabled on every request, I am looking for a way to expire that user's session so that the next request will require them to log in.

I believe this is controlled by a cookie. Is this possible?

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • Seems like you'd need some code that executes on every request. Which is what `Application_BeginRequest` is for. Write code there that checks the status of the user, then logs them out if they are disabled. Seems straightforward enough. Note that you'll want this to be a very speedy check since it will happen for every request. – mason Mar 28 '17 at 19:57
  • @mason: Yes, I considered that. That is probably a reasonable fall-back approach. Still, there would be a small performance hit there. I was sort of hoping someone who better understand how a user session is tracked might know a way to expire it. – Jonathan Wood Mar 28 '17 at 19:59
  • 1
    There's no magic that's automatically going to notice you flipped a field in your database and thus log a user out. You need to code it yourself. And if you want the check to happen every request, that's where you do it. I *suppose* you could do AJAX polling or SignalR or something to monitor the status of the user and listen for some sort of "User Disabled" event to be pushed from the server. You'd need a background process running that could send out the notification. Again, something you'll have to wire up and not out of the box. – mason Mar 28 '17 at 20:02
  • @mason: Magic? Somehow, ASP.NET tracks if a user's session is current, no? Obviously, I'd need to write code. I was wondering if I could write code to alter the data that says the user's session is current. – Jonathan Wood Mar 28 '17 at 20:04
  • Looks like I stand corrected by Igor. There is magic! – mason Mar 28 '17 at 20:08

1 Answers1

6

Actually this can be automatically done. In ASP.NET Identity in the user store there is a property called SecurityStamp. When you change this the user is forced to re-authenticate with the next request. This is because this field is used to generate the authentication token (cookie in your case). The framework has methods that are built into it for changing this either directly UpdateSecurityStampAsync as well as or indirectly. A good example of when it is changed indirectly is when the identity's password is updated through the framework (ie. calling UpdatePassword or RemovePasswordAsync), or when enabling 2 factor authentication for the identity.

The method to change the security stamp is can be found in the UserManager and is called UpdateSecurityStampAsync. From the documentation:

Generates a new security stamp for a user, used for SignOutEverywhere functionality.

Igor
  • 60,821
  • 10
  • 100
  • 175
  • Sounds interesting. Going to try and research this. – Jonathan Wood Mar 28 '17 at 20:05
  • The security stamp is also updated when the user changes the password forcing a log off from all locations. – Martin Liversage Mar 28 '17 at 20:09
  • @MartinLiversage - correct, maybe my wording of that was not clear? Let me see if I can re-phrase... – Igor Mar 28 '17 at 20:10
  • This sounds like it would work, but so far I'm not having any luck. I'm logged in as two different users using two different browsers on the same computer. My code looks something like `user.Disabled = true; await UserManager.UpdateSecurityStampAsync(userId); await UserManager.UpdateAsync(user);`. But when I run this code, I can still browse in the other computer without having to log back in. – Jonathan Wood Mar 28 '17 at 20:34
  • @JonathanWood - 1) Make sure that you are not running with a sync turned on in VS, this can cause browsers to sync with eachother and give you false-positives. 2) Verify the security stamp has changed in the data store after you call the update and then re-execute the request in the other browser. Alternatively you can try to force the update yourself in the DB manually with a query as its just a guid (just for testing). – Igor Mar 28 '17 at 20:37
  • 2
    @JonathanWood: See the answer to [How do I forcefully propagate role changes to users with ASP.NET Identity 2.0.1?](http://stackoverflow.com/a/24317054/98607) on how to configure ASP.NET Identity to validate the cookie immediately. – Martin Liversage Mar 28 '17 at 20:40
  • I could verify that the security stamp changed in the database. One browser is Edge and the other browser is Chrome, so I'm not sure how they could be in sync. Is there a setting somewhere? – Jonathan Wood Mar 28 '17 at 20:40
  • 1
    @JonathanWood - see @Martin's comment. Essentially you have to specify how frequently the validation is done using `validateInterval`. After testing you will have to specify a good balance between frequency and performance based on your needs. – Igor Mar 28 '17 at 20:41