Creating an interstitial login page with JqueryMobile

So, at work, we’re building a mobile website using JqueryMobile. The app has a bunch of publicly visible pages however, other pages require the user to be authenticated. We didn’t want the user to be forced to login on the first page. Instead, whenever a protected page is accessed, and if the user insn’t logged into the app, we’d like to take him to the login page. Once he’s successfully authenticated, then take him to the page he was navigating to. Doing this in a normal webapp is quite standard – however, with JqueryMobile, query params meddle with the hash navigation model. Also, the page that the user tries to access could be a div in the same physical page or a different url that needs to be fetched.

Trying to solve this was interesting as we were all really just getting started with JqueryMobile – so finding the ideal solution required a few tries. The solution takes a leaf out of JqueryMobile’s approach. The outline of the solution is:

  1. Any page div that’s a protected resource is marked with a data-needs-auth="true" attribute
  2. We hook into the document level pagebeforechange event to see if the user is trying to transition to a page requiring authentication. If so, then check if we have the user’s authenticated context available.
  3. if the said context isnt available,
    1. Cancel default event handling since we’re now going to navigate the user to the login page.
    2. save the toPage object – so once the user is logged in, we know where to take him.
    3. navigate to the login page.
  4. In the login page, the page can call the server apis to autheticate the user. Once the user is authenticated, then
    1. See if there’s a valid returnTo object, if so, take the user to the page.
    2. If not, take the user to a ‘default’ page – in our case, this is the app dashboard page.

Code below

    var pageVars = {}
    $(document).bind("pagebeforechange", function (event, data) {
        if (typeof data.toPage == 'object' && data.toPage.attr('data-needs-auth') == 'true') {
            if (!sessionStorage.getItem("TokenSSKey")) {
                if (!localStorage.getItem("TokenLSKey")) {
                    pageVars.returnAfterLogin = data;
                    event.preventDefault();
                    $.mobile.changePage("#Login_Page", { changeHash: false });
                }
                else {
                    sessionStorage.setItem('TokenSSKey', localStorage.getItem("TokenLSKey"));
                }
            }
        }
    });

The login event handler that handles the server response that’s received once we pass the username and password

    function SuccessLogin(data) {
        if (data != null && data.LoginResult != null) {
            if (data.LoginResult.Code === 0) {
                localStorage.setItem('UNameLSKey', data.LoginResult.User.AccountName);
                if ($("#RememberMeChkBx").is(":checked")) {
                    ErrorPanel.html("");
                    localStorage.setItem('TokenLSKey', data.LoginResult.Token);
                    sessionStorage.setItem('TokenSSKey', data.LoginResult.Token);
                }
                else {
                    ErrorPanel.html("");
                    sessionStorage.setItem('TokenSSKey', data.LoginResult.Token);
                }
                if (pageVars && pageVars.returnAfterLogin) {
                    $.mobile.changePage(pageVars.returnAfterLogin.toPage);
                }
                else {
                    $.mobile.changePage("#DashBoard_Page", { changeHash: false });
                }
            }
        }
    }

Advertisements

8 thoughts on “Creating an interstitial login page with JqueryMobile

  1. This is a very useful example of JQM. I have one question.

    Inside my JQM page, ‘/app1’, I have created footer tabbar in my JQM application that looks like this. (I actually used codiqa to generate this code, so results may vary if there is non-standard JS or CSS behind it.)

    Account Details
    Generate Invoice

    My “#page1” Account Details div is using the data-needs-auth attribute. Punters are correctly redirected to a login page using the pagebeforechange event specified above.

    I’d like to do a similar login check for the external link to “/app2”. In this case, I would the user to be redirected to login after they press the “Generate Invoice’ button, but before the HTML for /app2 is actually requested.

    Can you suggest a similar event binding so that I could assign a “data-needs-auth” attribute to the link?

      • @krisgest looks like what you’re asking is how to intercept a click on a link and force login?

        If that’s so, why do you create a page in your app with the data-needs-auth and once the user lands on the page, pull in the html for the page from the external link? (or redirect to the link – but then you lose all your page state)..

        If this ‘external’ link is something you control, you’d be better off consuming JSON from it…

        I’m sorry – but with out additional info, that’s all I can venture… drop me a PM at raghu dot rajagopalan at dot com

  2. I’m a bit confused by the email address you supplied in the above post.
    I think it is missing part of the domain.
    I transcribed: rxxxx.rxxxxxxxxx@.com

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s