1
votes

Currently I am working on a Facebook app and it's developed by using ASP.NET.

This app works fine with IE(7,8 and 9) FF and Chrome.

The first page is default.aspx and it will handle the authentication then redirect to home.aspx

Now the only issue it has is that Safari doesn't accept cross-domain cookies. I've changed the web.config file and add it in order to avoid the use of cookies.

After that, the URL comes to http://www.testdomain.com/(S(gvsc2i45pqvzqm3lv2xoe4zm))/default.aspx

It just can't be redirect from default.aspx to home.aspx automatically...

Anyone got a clue?

Or, is there anyway that i can deal with Safari with ASP.Net session in Facebook app?

Tons of thanks

PS. The code from default.aspx page

protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { if (!string.IsNullOrEmpty(Request.Params["signed_request"])) { string signed_request = Request.Params["signed_request"]; if (!string.IsNullOrEmpty(signed_request)) { // split signed request into encoded signature and payload string[] signedRequestParts = signed_request.Split('.'); string encodedSignature = signedRequestParts[0]; string payload = signedRequestParts[1];

                // decode signature
                string signature = decodeSignature(encodedSignature);
                // calculate signature from payload
                string expectedSignature = hash_hmac(payload, Facebook.FacebookApplication.Current.AppSecret);

                if (signature == expectedSignature)
                {
                    // signature was not modified
                    Dictionary<string, string> parameters = DecodePayload(payload);
                    if (parameters != null)
                    {
                        string UserId = parameters["user_id"];
                        Session.Add("UserId", _SystemUser.SystemUserId);
                        Session.Add("Username", _SystemUser.Username);
                        Response.Redirect("Home.aspx?user_id=" + UserId);
                    }
                }
            }
        }

        if (!String.IsNullOrEmpty(Request["error_reason"])) // user denied your request to login
        {
            logger.Debug("Error Reason: " + Request["error_reason"]);
            //User denied access
        }

        if (String.IsNullOrEmpty(Request["code"])) // request to login
        {
            string url1 = String.Format("https://www.facebook.com/dialog/oauth?client_id={0}&redirect_uri={1}&scope={2}", Facebook.FacebookApplication.Current.AppId, callbackUrl, ext_perms);
            Response.Redirect(url1);
        }
    }
}
3

3 Answers

1
votes

When using cookieless sessions, ASP.Net will automatically redirect any requests without a session ID in the URL to the same page, but with a new SessionID in the URL. However, it redirects as a GET request, and thus does not forward on any POSTED parameters ... so after the redirect your "parameters" variable, from the decoded signed_request, will be missing because the page will no longer have the signed_request POSTed parameter.

There are two possible solutions to this (that I know of):

  1. Intercept the initial redirect in Global.ascx, and instead do your own redirect with the new SessionID in the URL ... BUT, do this as a self-posting form in Javascript where the form also has a signed_request param with the value of the signed_request.

  2. Turn cookie sessions back on, and in your first page redirect out of FB to a page. In this page set a Session variable (which will get ASP.Net to set a session cookie), and then redirect back into FB.

You may/will also need some code to handle any app_data, if this is on a tab page too.

Sorry I can't be more useful code wise. I've written my own handlers for my job, but my workplace now owns that code! I'm never sure how much is OK to share.

0
votes

I used cookieless session, but as the initial page was getting refreshed, the Facebook "signed_request" POSTed to the landing page was lost.

As a workaround, I added an HTTPModule to override EndRequest() event. In the event if the page is "initial page" & contained "signed_request" POSTed, the value is added as querystring. In the page we would check the querystring value and set it into session, to be used in the application.

The EndRequest is as below:

void context_EndRequest(object sender, EventArgs e)
{
    HttpContext cntxt = HttpContext.Current;
    const string paramname = "signed_request";
    const string initialPage= "/startapp.aspx";
    if ((String.Compare(cntxt.Request.Url.AbsolutePath, initialPage, true) == 0) && (!String.IsNullOrEmpty(cntxt.Request[paramname])))
    {
        string strQuerySignedReq = paramname+"=" + cntxt.Request[paramname];
        if (cntxt.Response.RedirectLocation.Contains(".aspx?"))
            cntxt.Response.RedirectLocation = cntxt.Response.RedirectLocation + "&" + strQuerySignedReq;
        else
            cntxt.Response.RedirectLocation = cntxt.Response.RedirectLocation + "?" + strQuerySignedReq;
    }
}

The initial page - "startapp.aspx", load event would be:

protected void Page_Load(object sender, EventArgs e)    
{
   signed_request = Request.QueryString["signed_request"];
}

The disadvantage of the code is that EndRequest() would execute for all requests. Also, only relative url should be used for links. I have had several annoying experiences on cookies and Facebook, due to various security levels on different browsers. Hence, I can live with the disadvantages. Hope this helps!

0
votes

I know this is an old question, but I had exactly the same problem and found a solution. The solution here works if you're using a SQL Server in your application.

Using cookieless to store your SessionId in the URL will avoid the cookie problem, but still missing the Session issue in Safari.

Well, you'll need to set a SQL SessionState, this will make your application communicate with your Database to store the Sessions. This will work for facebook canvas apps in Safari.

Setting this is simple:

Registering: run aspnet_regsql.exe (in C:/Windows/Microsoft.NET/Framework/'Framework version'/) Check parameters in https://msdn.microsoft.com/en-us/library/ms229862.aspx (the main ones are -S –ssadd)

In the same path, there is a InstallSqlState.SQL script. Run it on your Database Server.

Now, set this tag in your Web.Config file:

<configuration>
  <system.web>
    <sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424" timeout="120" cookieless="true" />
  </system.web>
</configuration>

And the magic is done!

There is something to remember. You can't do WebRequests to facebook from Server side to request for access tokens, because facebook redirects the calls to the "Valid OAuth redirect URIs", and completely ignores the SessionId parameters in the Request URI. You still can make WebRequests to APIs, but the authentication will need to be assyncronous, using Javascript.