views:

96

answers:

1

Hi Guys,

I have a Facebook Connect (FBML) web application that has been live for a while now.

All is working well, however user's are reporting issues with the single sign on (and i have seen the issue on their computer, but have not been able to replicate locally).

With FBC, there is a "event" you can hook into to automatically determine if the user is authenticated to Facebook.

That is achieved via this:

FB.Connect.ifUserConnected(onUserConnected, null);

The onUserConnected function can then do whatever it needs to attempt a single sign on.

For me, what i do is a AJAX call to the server to see if the user has an active website account (based on the Facebook details - user id, which i store in my system when they connect).

If they do, i show a jQuery modal dialog ("Connecting with Facebook") and do a window.location.reload().

The server then kicks in, and does the Single Sign On. This code is executed on every page:

public static void SingleSignOn(string redirectUrl)
        {
            if (!HttpContext.Current.Request.IsAuthenticated) // If User is not logged in
            {
                // Does this user have an Account?
                if (ActiveFacebookUser != null)
                {
                    // Get the user.
                    var saUser = tblUserInfo.GetUserByUserId(ActiveFacebookUser.IdUserInfo);

                    if (saUser != null)
                    {
                        // Get the Membership user.
                        MembershipUser membershipUser = Membership.GetUser(saUser.UserID);

                        if (membershipUser != null && membershipUser.IsApproved)
                        {
                            // Log Them Automically.
                            FormsAuthentication.SetAuthCookie(membershipUser.UserName, true);

                            // At this point, the Forms Authentication Cookie is set in the HTTP Response Stream.
                            // But the current HTTP Context (IsAuthenticated) will read HTTP Request Cookies (which wont have the new cookie set).
                            // Therefore we need to terminate the execution of this current HTTP Request and refresh the page to reload the cookies.
                            HttpContext.Current.Response.Redirect(
                                !string.IsNullOrEmpty(redirectUrl) ? redirectUrl : HttpContext.Current.Request.RawUrl,
                                true);
                        }
                        else
                        {
                            HandleUnregisteredFacebookUser();
                        }
                    }
                    else
                    {
                        HandleUnregisteredFacebookUser();
                    }
                }
                else
                {
                    HandleUnregisteredFacebookUser();
                }
            }
        }

I have never experienced an issue with this, but user's are reporting an "infinite" loop where the dialog gets shown, the window is refreshed, dialog is shown, window is refreshed, etc.

Basically, my AJAX call is saying the user exists, but my single sign on isn't.

Which is hard to believe because the code is very similar:

This is the AJAX Web Service:

if (!HttpContext.Current.Request.IsAuthenticated) // If user is not yet authenticated
            {
                if (FacebookConnect.Authentication.IsConnected) // If user is authenticated to Facebook
                {
                    long fbId;

                    Int64.TryParse(Authentication.UserId, out fbId);

                    if (fbId > 0)
                    {
                        tblFacebook activeUser = tblFacebook.Load(facebookUniqueId: fbId);

                        if (activeUser != null && activeUser.IsActive) // If user has an active  account
                        {
                            return true;
                        }
                    }
                }
            }

So if the response of this WS is 'true', i do a window.location.reload();

So i have no idea what the issue is (as i cant replicate), sounds like the Single Sign On isn't adding the Forms Authentication cookie properly to the response stream, or the Response.Redirect(Request.RawUrl) isn't reloading the cookie properly.

How do other's handle this?

This is what should happen:

  1. User logs into Facebook (on Facebook itself)
  2. User comes to my site (which has been previously authorised)
  3. My site compares the FBID with the FBID in my DB, and signs them in.

My site is an ASP.NET 4.0 Web Forms application, using the "old" Facebook Connect JavaScript API (FeatureLoader.js), and Forms Authentication.

The only other solution to an AJAX call/window.reload i can think of is an AJAX UpdatePanel.

Can anyone help me out?

EDIT

Also, i realise that i can also use 'reloadIfSessionStateChanged':true to do the reload (which stops the infinite loop), but the problem with this is i cannot show my nice fancy dialog.

A: 

So i found a couple of issues.

Firstly, i shouldn't be setting a persistent cookie:

FormsAuthentication.SetAuthCookie(membershipUser.UserName, true);

We should only do this when the user ticks a box such as "Remember Me".

Secondly, i was checking the FB Auth status on every page on the server, so this could have been getting out of sync in the client-side.

Here is my new solution - which is better, and has a failsafe for the dreaded 'infinite loop'.

I no longer check the FB Auth status on the server, i do on the client:

FB.Connect.ifUserConnected(onUserConnected, null); // runs on every page request, on client-side

In the onUserConnection function i do the following:

  1. Call web service to see if user CAN be signed in automatically (same WS as above)
  2. If ok, check a special "Single Sign On" cookie has not been set.
  3. If it hasn't been set, redirect to FacebookSingleSignOn.aspx.

FacebookSingleSignOn.aspx does the following:

  1. Signs the user in using Forms Authentication (same as above)
  2. Creates a special "Single Sign On" cookie to signify a SSO has been attempted
  3. Redirects to the homepage

So, at point 3 above - this is where the infinite loop "could" happen. (as the onUserConnected will run again)

But it is now impossible (i hope) for it to happen, as it will only attempt to do the SSO if they havent already tried.

I clear the SSO cookie on the Facebook Logout action.

Now works well, logic makes sense - and it's done on the client-side (where it should be, as this is where FB does it's magic).

Hope that helps someone else out.

RPM1984