Edit:
Upon re-reading the question I see that I've misunderstood what the OP was really asking for. Leaving my original reply underneath, in case someone else finds it useful.
The proper answer to this questions is: Why care about who gets to see the login form? Just use a properly strong password, and the correct techniques for preventing brute-force attempts (throttle limiting).
Any secret key, or similar, you add to this script is just another password after all. Any other information derived from your connection, browser or whatever, can be sniffed and spoofed by an attacker (or even changed from underneath you, for any reason).
Limiting to a single (or range of) IP(s) is only really useful if you have a static IP, and want to make it a bit more difficult for any potential hacker to break your password.
It is not a replacement for a good password.
Original answer:
This is actually a rather common problem, and solved quite a few times. While it takes a bit of work to implement the solution, it is quite straight forward.
First off you need to create a table to keep track of the sessions for each user. This table needs only two (or three) fields:
- user id
- session id
- (timestamp)
The timestamp can be omitted as it's not essential, but it might be nice to have for debugging/logging purposes.
Once you have that you need to re-write your login script a bit. So that it first checks if the user has any active sessions already, if they don't then simply create a new session and store its ID in the abovementioned table.
However, if the user does have a session active already, then you need to do one of two things:
- If you want to disallow any further logins, simply return an error explaining that they are already logged in.
- Or, delete the old sessions and then log them in on the new device.
Of these two approaches I'd prefer the latter one, as the first one can lead to a user accidentally locking himself out of the system. Until you, as the administrator, go in and manually delete the old session.
The second approach will require a bit more work, in order to delete/invalidate the old sessions, but is generally more robust. It will also give the users the least amount of surprise, as they expect to be logged in when attempting to do so. Instead of having to go chase down whatever unit they think they logged in with last.
Another thing you could do, if you decide on approach 1, is to log the timestamp and then use this in conjunction with the max session lifetime. If time_now - max_session_lifetime > timestamp then you know the session is old, and can be deleted automatically. Ensuring that the user will, eventually, be able to log in without having to rely upon finding/getting the old unit, or you manually deleting it.
I won't post any code on this, for two reasons:
- You haven't posted the code in which you handle the logins, making it impossible for me to suggest any specific changes.
- The changes needs to be done in quite a few places, and requires a redesign of your logic.
However, follow my logic and set up a pseudo code/flowchart diagram and it should be quite easy to implement.