1

I currently am using a ConcurrentDictionary to hold a collection of login names that have authenticated with my API. I do this to prevent duplicate logins from other web clients (a requirement of the system architecture). If a user authenticates with a login that is already "logged in" they are given a choice ...

  1. Continue and the previous login will be expired
  2. Cancel and the current session will be logged out

I am using a ConcurrentDictionary because it is supposed to be thread safe which is important in an environment where multiple clients are accessing the API.

What I am asking is if the ConcurrentDictionary is needed because I am running into trouble deleting all items in the collection that match a given key. Is a ConcurrentDictionary called for in this case? If not, would a plain Dictionary suffice? If not, and a ConcurrentDictionary is needed is there a method that will remove all entries matching a given key? All I can see is TryRemove() which only seems to remove a single entry.

Luiso
  • 4,173
  • 2
  • 37
  • 60
webworm
  • 10,587
  • 33
  • 120
  • 217
  • 4
    There can only be one entry matching a key in a `ConcurrentDictionary`. – Lee Jun 15 '16 at 19:35
  • 4
    I mean no disrespect but your approach to authentication worries me. Web technologies like web-api are meant to be stateless. You should not be tracking who logged in in memory. I would rethink the authentication/authorization process entirely. Maybe look up some existing frameworks and examples, there are many. – Igor Jun 15 '16 at 19:36
  • @Lee - I wasn't even aware of that. Perhaps that is why there is no method to remove all. – webworm Jun 15 '16 at 19:37
  • @Igor - I would respectfully disagree with you. An API can be whatever you need it to be. It seems to be working well for us. – webworm Jun 15 '16 at 19:39
  • I'm with Igor on this one. Your clients should be supplying an authentication token that you gave them at some point. If you try to keep a list of who's logged in, how long are you going to maintain that list? what happens when you server restarts and you've lost the list? – n8wrl Jun 15 '16 at 19:39
  • The system does use JWT tokens. If they server is restarted then all users are logged out. Regardless, that is not the question that I asked about. – webworm Jun 15 '16 at 19:42
  • I agree with @Lee, a concurrentdictionary is still a dictionary under the covers, so you should only have 1 key to deal with. Are you seeing something otherwise? – John Bustos Jun 15 '16 at 19:43
  • Another thing to consider: will you ever have more than one web server running to handle load? – Berin Loritsch Jun 15 '16 at 19:43
  • Is a standard Dictionary thread safe? – webworm Jun 15 '16 at 19:45
  • @webworm - true, a web api can do whatever you need it to do but in coding there are general abstractions. Authentication is a well known abstraction and there are tried and tested approaches to authentication especially on Web API. Greater minds than yours (and mine) have come up with these approaches and they have been scrutinized. There is no need to re-invent the wheel and possibly open your service for an attack and also try to invent creative ways around problems that should not be problems to begin with. It will allow you to focus on what is important, creating a valuable api service. – Igor Jun 15 '16 at 19:45
  • 1
    @webworm, No. standard dictionary is not threadsafe – Berin Loritsch Jun 15 '16 at 19:45
  • @Lee Please add your comment as an answer and I will accept it as so – webworm Jun 15 '16 at 19:45
  • @Igor - How would you go about preventing logins from different clients without keeping track of who is logged in and who is not? – webworm Jun 15 '16 at 19:49
  • @webworm - You should not need to track who is currently logged in and who is not especially because web technologies are generally made to be stateless. For authentication and authorization you can use authentication bearer/access tokens. There are NuGet packages that can handle this on the server side for you. I found [this article](http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api) to be a good starting point. It illustrates both how to handle the authentication on the client as well as how to configure your Web API service with oauth2 support. – Igor Jun 15 '16 at 20:01
  • I agree with the others about making your API stateless. A great book on the topic of API authentication is Pro ASP.NET Web API Security from Apress. To your original question, yes you'll need ConcurrentDictionary to have thread-safe operations. And of course a Dictionary can only have one copy of a given key. That's its definition. – Spivonious Jun 15 '16 at 20:04

1 Answers1

1

The direct answer to your question:

Yes, you need a ConcurrentDictionary. You are sharing state across several threads.

Remember, a dictionary has one entry per key. That's the definition of what a Dictionary is, and a ConcurrentDictionary doesn't change that.

A fuller and more complete answer to your requirement is below.


The whole solution is short sighted as you have no connection with the session infrastructure to know when a user's session has timed out and effectively caused them to be logged out. Additionally there is no coordination with other instances of your app if you ever think about deploying to a cloud platform that spins up new instances.

In other words, you are putting yourself in a situation that makes it very difficult to scale your app without breaking this feature.

Probably one of the most robust ways of handling the single session requirement is to use your database:

  • Have a field that keeps track of the last session ID your user had when logging in.
  • Add a session listener to clear the field when the session times out
  • If the session ID is not the same as what's in the field, you know you have a new login attempt.
  • If you need complete control over the session ID, then supply your own session id manager (may be necessary to include an encoded server ID in it).

You'll find that the requirement is much more involved than it sounds on the surface. You can't think like a desktop application in the web space--which is precisely where this requirement even comes from.

Berin Loritsch
  • 11,400
  • 4
  • 30
  • 57
  • Wasn't even the question I was asking. The question was regarding the ConcurrentDictionary. – webworm Jun 15 '16 at 20:01
  • 1
    And the ConcurrentDictionary was the wrong answer. However, it is better than a standard Dictionary if it is holding shared state. – Berin Loritsch Jun 15 '16 at 20:04
  • I agree with @BerinLoritsch. If the server resets, the login creds of the user may still be valid but now you won't know about it because your dictionaries are empty. If you plan on scaling your application by providing load balancing across multiple hosts, the dictionary (concurrent or not) on one host can't see the dictionary on the other host. Granted you can force users to return to the same server, however, architecturally speaking, a Dictionary and a ConcurrentDictionary are the wrong approach. – Dave Jun 15 '16 at 20:58