Keep users from logging in on multiple devices

Is there a way in Perspective to keep users from logging in on multiple devices at once? I have a specification where “The SCADA client shall prohibit simultaneous logins with the same user account.”

I’m not sure how this could be implemented. Is there a subsystem in Ignition that tracks who’s currently logged in in the built-in IDP?

If there isn’t a built in system, I guess you could use session startup and shutdown events to add/remove the current user to a list that you’d store in a tag, and instantly log out the user if he’s already in the list…
It’s ‘a bit’ dirty, but if you can’t find a better option…

3 Likes

For clarification, do you need to log out other sessions, or do you need to prevent this attempt at logging in?

The specification doesn’t specify so at this point we can do whatever is easiest to implement. If I want to be really nice I could do both and have a message box with a couple buttons to let the user choose. But that’s not specified, so I’d go with the path of least developmental resistance.

As long as it is acceptable to logout any other session which is attached to the user currently attempting to login, this should be pretty easy with a change script on session.auth.user.username. You could make your script something like this:

# find all sessions which are using this user's username
for session in system.perspective.getSessionInfo(currentValue.value):
    # and log them all out
    system.perspective.logout(sessionId=session["id"])
1 Like

Great, thank you!

Actually it doesn’t seem to work for me. I can still have many users open.

What do you see if you log currentValue.value for these sessions?

Update: It looks like that property doesn’t technically “change” if the project requires authentication because the property initializes as the username, instead of initializing as some other value and then changing to the username. Let me see if I can do it some other way.

I conducted some research. And I made a few interesting discoveries (well, to me anyway). I created duplicate logins three different ways to the session. The first was two tabs logged into the same account on the same web browser (edge). Then I logged into the account on a different web browser. And then I logged into the project on a completely different computer (on the same network, of course).

(see images below)


It seems that logins from different PCs and different web browsers count as different sessions, but logins on the same web browser (different tabs) count as the same session, but have different IDs.

There’s a complicated nesting hierarchy.
One session can have many pages (in a browser, each tab will be a distinct page, with its own ID).
Each page can have many views.
Each view can have many components.

I wonder if it should instead look to see if the username matches and session ID is different. This interface doesn’t open new tabs so it should keep the same session for each login.

There’s not really a “clean” way to do this through Perspective, because we’re trying to use the session to solve an IdP problem; the Identity Provider should be preventing the user from logging in a second time, or managing previous logins.

One solution:

  • create a new custom session property: session_limiter.
  • Bind session_limiter with the following expression binding: {this.props.auth.user.userName} != null and Script transform:
def transform(self, value, quality, timestamp):
	for session in system.perspective.getSessionInfo(usernameFilter=self.props.auth.user.userName):
		if (session["sessionScope"] != "designer") and session["id"] != self.props.id:
			system.perspective.closeSession("You are limited to only one session at a time.", session["id"])
			return True  # denotes a session was closed during execution of the binding
	return False  # denotes no action was taken

If you go this route, I highly recommend requiring re-authentication in the Project Properties, otherwise you’ll likely encounter users unintentionally re-authenticating as the previous user. In the menu bar, see Project > Project Properties > Project > General

2 Likes

A proposed secondary solution, assuming the project will always require authentication:

  • Configure a Session Startup Event, and supply the following code:
def onStartup(session):
	for session_obj in system.perspective.getSessionInfo(usernameFilter=session.props.auth.user.userName):
		if (session_obj["sessionScope"] != "designer") and session_obj["id"] != session.props.id:
			system.perspective.closeSession("You are limited to one session at a time.", sessionId=session_obj["id"])

This solution worked! This is excellent, thank you. I wasn’t able to get the onStartup solution to work, but the primary solution works as intended.

Ah, there was a typo. I’ll update it.

Great, thank you! This solution seems to work even better. I was having issues with the previous one, though I’m not sure if I accidentally changed something with it.