Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I control website page access that works with the browser back button

I am using java script in the "head" section and sessionStorage variables to control the viewing of my web pages; to ensure proper login and prerequisite events are executed. In this this example I will be using 3 pages, the Default, Login and Menu pages.

The object is to prevent direct access to the Login and Menu pages via the address bar without accessing the Default page first.

The default page has the following conditions:

  <head>
    <script>
      <!-- Page Access Check -->
      sessionStorage.Page="Default";
      if(sessionStorage.MemberData){
        sessionStorage.Page="Menu";
        location.assign("Menu.asp");
      }
    </script>
  </head>

The Default page is the web site's access point, all users must enter there. The sessionStoreage.Page variable indicates the page allowed to be displayed. The purpose of this variable will become more apparent in subsequent code examples.

The sessionStorage.MemberData will be set if the current user has already successfully logged in and therefore does not need to log in again. Thus the sessionStorage.Page variable is set to "Menu" and the user is directed to the Menu page.

  <body>
    <script>
      $(document).ready(function(){
        <!-- Initialize Event Handlers -->
        $("#LoginButton").one("click",function(){
          sessionStorage.Page="Login";
          location.assign("Login.asp");
        });
      });
    </script>
  </body>

The Default page has a button linking to the Login page and, upon successful login, takes the user to the Menu page. The Login button sets the sessionStorage.Page variable to "Login" and directs the user to the Login page.

  <head>
    <script>
      <!-- Page Access Check -->
      switch(sessionStorage.Page){
        case "Login":                   // Page Allowed
          break;
        default:
          history.back();
      }
    </script>
  </script>

Upon arriving at the Login page, the sessionStorage.Page variable is checked and if the value is set to "Login" access to the page is granted. Otherwise the user is directed back to the page they came from, either the Default page of the page they were on previously.

    sessionStorage.MemberData=JSON.stringify(MemberData);
    sessionStorage.Page="Menu";
    location.assign("Menu.asp");

Upon successful login the sessionStorage.MemberData is set (refer to the check in the Default page), the sessionStorage.Page variable is set to "Menu", and the user is directed to the Menu page.

  <head>
    <script>
      <!-- Page Access Check -->
      switch(sessionStorage.Page){
        case "Menu":                     // Page Allowed
          break;
        default:
          history.back();
      }
    </script>

Upon arriving at the Menu page, the sessionStorage.Page variable is checked and if the value is set to "Menu" access to the page is granted. Otherwise the user is directed back to the page they came from, in most cases the Login page.

    <script>
      $("#LogoutButton").one("click",Logout)

      function Logout(){
        sessionStorage.removeItem("MemberData");
        history.back();
      }
    </script>

The Menu page has a Logout button that erases the sessionStorage.MemberData variable and returns the user to the previous page, the Login Page.

Since the sessionStorage.Page value is still set to "Menu" the Page Access Check of the Login page sends the user to it's previous page, Default.

These pages need to play nice with the browser back button.

  <head>
    <script>
      <!-- Page Access Check -->
      switch(sessionStorage.Page){
        case "Menu":                    // Page Allowed
          break;
        case "Admin":                   // Back From
          sessionStorage.Page="Menu";
          break;
        default:
          history.back();
      }
    </script>
  </head>

In this example, the user can use the back button to navigate from the Admin page back to the Menu page. In this case the sessionStorage.Page variable is still set to "Admin" and the check would fail. The subsequent check allows for a successful return from Admin.

Now, with all that said, here is the problem: The browser history stack is not working as expected.

From a new browser tab I navigate to the Default page. Checking the history stack I can see where "New Tab" is the previous page and there is no next page.

*Default
 New Tab

Clicking the button Login button on the Default page takes me to the Login page. The history stack now shows "Default" and "New Tab" for the previous pages and no next page.

*Login
 Default
 New Tab

Clicking the back button returns me to the Default page. The history stack now shows "New Tab" for the previous page and "Login" for the next page.

 Login
*Default
 New Tab

Clicking the forward button to advance to the Login page returns me to the Default page. This is because the sessionStorage.Page variable is still set to "Default". The history stack remains unchanged.

After successfully logging in and advancing to the Menu page the history stack now shows "Login", "Default", and "New Tab". There is no next page.

*Menu
 Login
 Default
 New Tab

All is working as expecting up to this point.

From the Menu page, I click the back button. What I see happening is what I expect: I am sent back to the Login page and because the sessionStorage.Page variable is still set to Menu, the Login page sends me back to the Default page. Because the sessionStorage.MemberData variable exists I am sent to the Menu page.

So, here is what I expected the history stack to contain:

             Back         Back        Assign

*Menu        Menu        Menu       *Menu
 Login      *Login       Login       Default
 Default     Default    *Default     New Tab
 New Tab     New Tab     New Tab

However, this is the actual condition of the history stack.

 Menu
 Login
*Menu
 New Tab

In the page access check in the Default page, which sent us to the Menu page, it appears that a "location.replace" was performed instead a "location.assign".

This is breaking my page navigation as clicking the Logout button on the Menu page takes me to the New Tab instead of the Default page.

The history stack is a Last In First Out stack. As you navigate from page to page the previous page address is placed on the stack. As you go Back, the pages are reloaded in the Last In First Out order.

Normally, with a LIFO stack, each time you go Back, that entry should be removed from the stack. But this would prevent you for returning to the original page with the Forward button. And as long as none of the entries in the stack are changed you can traverse up and down the history stack at will.

However, if you modify an entry, all entries Forward of that point become invalid and should be removed as you have not established a "Forward" path from that new page. And since the modified entry was assigned it should be placed on top of the current page instead of replacing it and all other entries above it should be removed.

Update:

The issue may stem from a timing issue. The question is "When is the address placed on the History stack?"

As with jQuery, some code can only execute after the page is ready. Perhaps, because the page is being redirected during the processing of the header, before the document is ready, the code that updates the History stack has not had an opportunity to execute.

Any thoughts on this point?

Update 2:

I tried moving the Page Access Code from the HEAD to inside the jQuery

$(document).ready(function(){...});

hoping that this would delay the location.assign() until after the page was fully loaded and thereby allow for the History to be properly updated. That did not solve the problem.

The location.assign("Menu.asp") is still replacing the Default.asp entry in the stack. Furthermore, I've noticed that the Forward entries are not being removed from the stack as I believe they should be whenever the stack is altered.

 Menu   <- Not Removed
 Login  <- Not Removed
*Menu
 New Tab

Perhaps someone has an alternate method that would work?

Howard Parr Caddo Mills, TX

like image 615
Howard Parr Avatar asked Nov 06 '22 12:11

Howard Parr


1 Answers

The unexpected behavior seems to me to be caused by the combination of history.back() and location.assign(), as you go through the history stack and assigning there a new site, this is as if you would create a new entry in the history's timeline.

If this i the case i would rather expect the history stack to look like this:

     Menu
     Login
     *Menu
     Default
     New Tab

Default automatically assigns to history.back(), therefore it is like an invisible step here - it actually is there, but always Menu is reached, when you go back to it.

like image 167
mZed Avatar answered Nov 12 '22 14:11

mZed