What you're actually trying to solve isn't as easy as it sounds, and going by MAC address isn't a good idea.
First off, some quick facts about MAC addresses as a whole:
- They only show up to the first hop on a network. The moment there is a routing device in the way, all you'll see is that device's MAC, as everything from then on is routed, not bridged
- That hop could be anything, depending on how far away (or how convoluted the network topology is) - a routing device of some sort from your ISP, something from an IX, etc
As a result, it's honestly not the best discriminant to use. Josh suggested one, I'll suggest another.
In your user storage, wherever that may be, add the ability to store an array. In most relational databases (if you're using that), it'll come in the form of an additional table. Make it easy to search for the entries corresponding to a user.
For simplicity's sake, here is the idea. This is your users table:
+---------------------------------------------------+
| users |
+----+----------+---------+------------+------------+
| id | username | enabled | created_at | updated_at |
+----+----------+---------+------------+------------+
We're going to create user_tokens
to go with it:
+-------------------------------------------+
| user_tokens |
+-------+---------+------------+------------+
| token | user_id | created_at | updated_at |
+-------+---------+------------+------------+
This table should promote fast access to all tokens for a given user, and the tokens should not be unique across all users, just one, so we're going to use (user_id, token)
as a composite primary key. We're also going to have to be able to delete the oldest tokens, so you're going to want to add (user_id, created_at)
as an index.
Whenever a new user logs in, create a new token and store it with their session (or session alternative). If there are more than N sessions, remove the oldest tokens to match the count.
Whenever a request is made, check if the token exists in the table. If it does not, then your user is simply not logged in. Due to the lightweight nature of this table, lookups should not be perceivable in terms of response times.