3

如果您想知道“比赛条件”是什么,它是系统中的一个缺陷,而它高度依赖于时间。有关更多信息,请参阅此处的 wiki 。

因此,我的条件与 Facebook Connect 和使用 ASP.NET 4.0 Web 应用程序(基于表单的身份验证 - IIS7)实现单点登录服务有关。

该过程本身(包括注销)运行良好,但是......

这是它不能完全 100% 工作的场景:

  1. 用户登录 Facebook。
  2. 用户导航到我的网站。
  3. 用户未自动登录(应该是)。
  4. 用户刷新页面,并自动登录。

当我在步骤 3 中对代码进行断点时 - Facebook Cookie 还不存在(在 中HttpContext.Current.Request.Cookies)。

但是当页面重新加载时(第 4 步) - Facebook Cookie 就在那里。

对我来说,可能有很多方面:

我不确定这只是 Facebook尚未授予访问我的应用程序以访问 cookie 的情况(跨域握手延迟 - xd_receiver.htm),还是跨域 cookie 本身和 ASP 的问题。 NET 页面生命周期。

其他人处理过这个问题吗?

这不是“万能的”,但它很烦人(从用户的角度来看也不是很好)。

编辑:

好的,我现在注意到了一些奇怪的事情。如果我登录 Facebook(通过 Facebook),然后等待 20 秒,然后转到我的网站,它仍然没有让我登录。只有在第二次加载后它才会让我登录。所以也许这不是时间问题 - 为什么是否需要 2 次刷新才能读取 cookie?

为了消除一些混乱 - Facebook 设置 cookie(用户登录到 Facebook),我的网站读取这些 cookie。

这发生在每个页面请求上(每个页面上的用户控件中的逻辑)

protected void Page_PreRender(object sender, EventArgs eventArgs)
{
   if (FacebookUser.IsAuthenticated) // static property, checks HttpContext.Request.Cookies
   {
        // log them into my website
   }
}

因此,在第一次刷新时 - HttpContext.Request.Cookies 中没有任何内容。

在第二次刷新时,它们就在那里。

我认为这是因为 FB.Init 是在每个页面请求的客户端执行的。这就是初始化 cookie 的原因。因此,当您第一次访问我的网站(登录 Facebook 后)时,在服务器端(我在其中检查 cookie),此功能尚未运行。

所以我认为我在这里打了一场失败的战斗(试图访问cookie服务器端,即设置客户端)。

编辑2:

这是我的初始化代码(在 window.load 上运行):

FB.init('myapikey', 'xd_receiver.htm', null);

我现在正在尝试做这样的事情:

FB.init('myapikey', 'xd_receiver.htm', null);
FB.getLoginStatus(function(response) {
  if (!response.session) {
      return false;
  }
  else {
    window.location.reload();
  }
});

但是我收到一个 JavaScript 错误 - “FB.getLoginStatus”不是一个函数。=(

这是因为我使用以下 JavaScript 库: http ://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php/en_US

而其他人说要使用这个: http ://connect.facebook.net/en_US/all.js

我正在查看新 JS API 的文档。

为了参考其他偶然发现这个线程的人,这里是“旧”JS API 的文档:http: //developers.facebook.com/docs/reference/oldjavascript/

因此,如果用户通过身份验证,我已经通过使用 FB.Connect.get_status() 和重新加载窗口解决了这个问题。

感谢大家的帮助。

如果其他人关心,这是我对问题的“解决方案”:

window.onload = function() { 
                FB.init('{0}', 'xd_receiver.htm');
                FB.ensureInit(function() {
                   FB.Connect.ifUserConnected(onUserConnected, onUserNotConnected); 
                });
            };

            function onUserConnected() {
                alert('connected!');
                window.location.reload();
            }

            function onUserNotConnected() {
                alert('not connected');
            }

当然,您应该在执行 window.location.reload() 之前检查 Forms Authentication cookie,否则页面将一直刷新。=)

4

4 回答 4

1

这不是“竞争条件”,可以更好地描述为基于浏览器的身份验证如何工作的副作用。这里涉及三个“演员”:

  1. 你的申请
  2. Facebook
  3. 用户

当用户访问您的应用程序时,Facebook 尚未参与该过程。这意味着您不知道用户是否是已经授权您的应用程序的 Facebook 用户,因为 Facebook 还没有机会告诉您。这就是您在第一个请求中没有收到任何 cookie 的原因。

现在,当您的应用程序响应此请求时,它会在其中包含 Facebook JavaScript。JavaScript SDK将使用 IFrame(如果您告诉它使用该status: true选项更明确地)在后台 ping Facebook,并根据当前登录 Facebook 的用户(如果有)从它那里获得响应。此时,如果返回会话(即,有一个登录用户过去曾授权过您的应用程序),Facebook JavaScript SDK将设置一个 cookie(如果您使用选项告诉它这样做cookie: true)。

这就是为什么第一个请求没有得到 cookie 背后的逻辑。除了设置 Cookie 之外,您还可以通过JavaScript 事件获得通知,这将允许您采取某些操作。最常见的操作是简单地重新加载页面并允许服务器注意到新设置的 cookie 并呈现适当的登录视图。但另一种选择是使用 Ajax 并做一些不涉及重新加载整个页面的更有趣的事情。

至于为什么它只在第二页加载时发生,我不确定。但这就是它的设计工作方式:)

注意:我没有进入高级使用场景,它涉及到完整页面重定向到这样的未记录但受支持的端点(与 JavaScript SDK 使用的端点相同),这提供了修复此问题的错觉。我强烈推荐使用 JavaScript SDK,因为它以很小的可用性成本提供了一个更简单且通常性能更高的解决方案。但如果你足够关心,我也可以详细说明。

于 2010-07-19T23:09:57.390 回答
0

由于您无法控制竞争条件的入口点(用户登录到 facebook),因此您可以执行的选项数量有限:

  1. 在第 3 步添加延迟(也许几毫秒的睡眠会给 Facebook 足够的时间来登录您的使用)。这将产生部分修复的不良影响:它将适用于“大多数”情况,并且会导致您的所有登录延迟。

  2. 如果在第 3 步身份验证失败,则等待几毫秒(测试以找到正确的数量),然后再次尝试进行身份验证。然后才显示未验证的页面。

  3. 如果这是一个页面生命周期问题(不太可能),请为您的登录页面添加一个额外的页面/重定向。这意味着您的流程将如下所示:

    a) 用户登录到 facebook
    b) 用户导航到您的网站(cookie 尚未设置)
    c) 用户被重定向到登录页面(cookie 可能已设置)。如果用户尚未通过身份验证,请等待 100 毫秒,然后重定向到步骤 b)(仅一次)。
    d) 用户已登录

于 2010-07-19T07:00:46.307 回答
0

我有完全相同的问题。你能找出原因吗?令人惊讶的是,它适用于我的生产服务器,但不适用于本地主机(由于本地主机相关问题,我已将 /etc/host 更改为将本地主机称为 peta.edu)

多次刷新对我也不起作用。但是,如果我手动单击 URL 栏并按 Enter,它就可以正常工作。

问候,

尼廷。

于 2010-08-18T14:39:13.867 回答
0

我遇到了同样的问题。页面重新加载工作的原因是因为它们导致 FB.init() 再次被调用(我怀疑这是实际设置 cookie 的函数)。

因此,您无需重新加载页面即可实现相同的效果。这是我所写内容的程式化版本。我不知道这是否是“正确”的方式,但它确实有效......

FB.getLoginStatus(function(response) {
    if (response.session) {
       window.location.href = '/connect/cb/fb'; 
    }
    else{
       FB.login( function(resp){FBResponse(resp);},perms);
    }
});

var FBResponse = function(response,stop){ if (response.session){ window.location.href = '/connect/cb/fb'; } else{ if (stop) return; FB.init({appId:FBappId, status:true, cookie:true, xfbml:true}); FB.getLoginStatus(function(resp){FBResponse(resp,'stop');}); }; }

于 2010-08-18T18:16:41.233 回答