How to prevent a user from having multiple instanc

2019-01-14 22:54发布

问题:

I'm wondering if it is possible to determine if a user already has a web browser open to the web application I'm working on. It seems that they can open several instances of the same web app and click on buttons to read information that they have used before to enter into an input screen that they're currently working on.

What happens though is that it seems to screw up Session variables and then the user will update their previous work with their new work. Or they will delete their previous work all together or who knows...

EDIT I have seen this done before with online banking web applications. If you are already logged in, the new window will kindly tell you that you already have the app open. In my case, the user does not need to log in.

Is there a simple way to determine if they already have a browser window open to the web application and if so, just close the browser or display a different page to let them know they can only have 1 open at a time?

Thanks

回答1:

Firstly, no there isn't, and secondly, you shouldn't try.

The pop-up window strategy won't work (and will annoy users). I have my browser set to 'Open windows as Tabs', and I choose whether to split one off into another window. Or in some cases, whether to run a different browser -- not just another instance of the same one -- to display another page on the same site.

Conversely, the mini-session ID will fail because the server can't keep track of whether a request is from the same user as an existing session. Several people may be using the same machine, even with the same username; or one person may have several separate login sessions, on one or several machines.

Just sort out your protocol vs. 'Session' variables and make sure that the last committed changes are the ones that persist.



回答2:

Is there a simple way to determine if they already have a browser window open to the web application and if so, just close the browser or display a different page to let them know they can only have 1 open at a time?

In short, No.
Without writing some kind of activeX control, there is no code you could write that could stop the user from opening a (seperate instance of) IE/FF etc and having one instance detect the other.



回答3:

You could assign a 'mini-session' ID to each instance of the input form, then use AJAX to ping the server with that ID. If the user tries to request the same form when there's an active ID, it should display an error message. If the server doesn't hear the ping for a certain amount of time, expire the mini-session. (This is basically a very simple locking strategy)



回答4:

All you have to do is assign a value both to a Hidden Input control's value and to a session variable in the Page Load event and on postback, check the value of the local variable against the value in the session variable. If the values do not match, you can redirect the user to the login page or a page that tells them that the session for that page is no longer valid etc.

Example:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Try
        If Not IsPostBack Then
            'SET LOCAL VARIABLE AND SESSION VARIABLE TO A UNIQUE VALUE
            'IF THE USER HAS CHANGED TABS THIS WILL CHANGE THE VALUE OF THE SESSION VARIABLE
            Me.HiddenInput.value = New Guid().ToString
            Me.Session.Add("PageGuid", Me.HiddenInput.value)

        Else 
            'ON POSTBACK, CHECK TO SEE IF THE USER HAS OPENED A NEW TAB
            'BY COMPARING THE VALUE OF THE LOCAL VALUE TO THE VALUE OF THE SESSION VARIABLE

            If me.HiddenInput.value <> CType(Session("PageGuid"), String) Then

                'THE VALUES DO NOT MATCH, MEANING THE USER OPENED A NEW TAB.
                'REDIRECT THE USER SOMEWHERE HARMLESS

                Response.Redirect("~/Home.aspx")

            Else

                'THE VALUES MATCH, MEANING THE USER HAS NOT OPENED A NEW TAB
                'PERFORM NORMAL POSTBACK ACTIONS

                ...

            End If
        End If
    Catch ex As Exception
        Me.Session.Add("ErrorMessage", BusinessLogic.GetErrorMessage(ex))
        Me.Response.Redirect("~/ErrorPage.aspx", False)
    End Try
End Sub


回答5:

I use the trick of opening a new window with a specific ID and always make sure that any page will open always use that window.

The down side, they must have their popup blocker turned off for you site. It works well for company sites.

if (useOwnWindow && window.name != 'YourAPP'){
    var w = window.open(document.location, 'YourAPP', 'toolbar=no,status=yes,resizable=yes,scrollbars=yes');
    if (w==null){
        alert("Please turn off your pop-up blocker");
    }else{
        window.open('','_parent','');
        self.opener="";
        self.close();
    }
 }

Note the useOwnWindow flag if used by developers so we can open it multiple times



回答6:

I would suggest you hash the ViewState for the page and store it in a session variable before it is returned as the Response.

Then for a Request first check the hash of the returned ViewState against the one you have in the session variable and if they don't match don't process any changes on the page and display a notice to your user or redirect them to an error page.

The two methods of the Page class you will want to override are;

protected override object LoadPageStateFromPersistenceMedium()

protected override void SavePageStateToPersistenceMedium(object viewState)


回答7:

We have implemented a solution to this problem on the slicethepie.com. Users (or "scouts") are only allowed to have one browser window open at a time to ensure they listen to the music they are being paid to review.

When a scout requests the first track to review in their scouting session we set a new Guid on their account and return this "key" along with the details of the track they're being given to review. It happens that the recipient of this key is a flash movie, but it doesn't have to be. The key is re-submitted along with the scout's review, and we check to see if it matches the saved key. If it doesn't they've started a new scouting session in a new window.

I'm not implying this method is foolproof, but it could be adapted to your needs quite easily.



回答8:

As others has mentioned, you can't prevent the user from starting a new session without resorting to ActiveX or other nastiness. The basic problem is that there is no way for you to know whether a user closed the old browser window or left it open.

What you can do however, is to invalidate the previous session as soon as the user logs into a new (A bit similar to how may Instant Messaging clients behave).

On each login, assign a new GUID to the user in your database. Also store this GUID in the session cache (No need to ship it back and forth to the pages, which won't work for GET requests anyway). On each page request, compare the GUID assigned to the user in the database with the GUID in the session cache. If they don't match, return a "You have logged in from somewhere else" response.

Update I was a bit too fast on the trigger. This doesn't prevent the scenario where the user opens multiple tabs/windows within the same browser process. So you would have to combine this solution with Dave Anderson suggestion for storing a ViewState hash (or simply a GUID) so that only the last served page in a session is allowed to post back.

Security Update Also, you can only rely on this framework as a convenience to the user since it's not secure. Any half decent hacker will be able to circumvent these measures.



回答9:

You can stop the page functionality when user opened another tab or another window or even another browser

  $(window).blur(function(){

// code to stop functioning or close the page  

});


回答10:

I partially solved the problem this way. My app ask users for authentication... so they type in a username and a password. When they click the submit button I store both data into session variable, i.e. I store username into Session("LoginName").

So here is the trick: just test if Session("LoginName") has a value BEFORE user enter it, in the page load event of login page. If so, this is a multiple session and you can stop the user or whatever.

Something like (I use VB):

    If Not Page.IsPostBack Then
       Try
          If Session("LoginName") <> "" Then
             Response.Redirect("www.mysite.com")
             Exit Sub
          End If
       Catch ex As Exception
          ' Do something
       End Try

PRO: very simple

CON: user can copy the address of an inner page and paste it to another tab of the same browser... this is why I said "partially"



回答11:

You could check if a the user has more than one active session. This might work, but could be problematic since there's no good way to determine if a session is really active or not.



回答12:

If someone copy the website url and paste it in a new window or tab, the browser history for that window/tab will be empty... so you can use javascript and check the history..

if (history.length == 1) {  //0 for IE, 1 for Firefox
    // This is a new window or a new tab.
}

Now you can prompt the user to close the tab, or disable that page (by making all elements disabled for example).



回答13:

I had the same problem and solved it using web sockets (I use pusher with php). When the user lands on the page I set a variable:

var firstTimeHere = true;

Then I made a websocket function in javascript that has the userid as part of the function's name like:

var pingUser123 = function(){...}; 

Then I use ajax to query the server where the php side of the websocket is triggered:

$this->trigger("pingUser123");

The websocket triggers all the javascript instances of that function in any number of windows across any number of browsers and machines. From there I can see if it's the first time this browser has been pinged. if so it's the only instance, if not there's a second one.

var pingUser123 = function(){
    if(firstTimeHere){
       firstTimeHere = false;
    }else{
        app.stop();
        alert("Only one window at a time please.");
    }
};


回答14:

 <script type="text/javascript">
        window.onload = function(){
        if (document.cookie.indexOf("_instance=true") === -1) {
        document.cookie = "_instance=true";
        // Set the onunload function
        window.onunload = function(){
            document.cookie ="_instance=true;expires=Thu, 01-Jan-1970 00:00:01 GMT";
        };
        // Load the application
        }
        else {
             alert(" Security Alerts.You Are Opening Multiple Window. This window will now close.");
             var win = window.open("about:blank", "_self"); win.close();
        // Notify the user
        }
        };
    </script>


回答15:

You can do this by window.name. In java script window.name has blank value on each new tab. Set window.name value on login page and save in session.

window.name = Math.random() + "_YourApplication"

Now check this window.name on master page/Layout page. Log out user if it contain multiple tab.

 if (!window.name || window.name != '@Session["WindowName"]') {
    //Log Off code
 }