Facebook画布应用程序无法保存会话

6
我制作了一个测试Facebook应用程序,只是为了玩一下,并使用会话来存储身份验证。我正在使用Omniauth。当我从http://fbbtest.heroku.com/登录,然后刷新页面时,会话仍然保存,并显示我已登录。当我尝试从画布http://apps.facebook.com/herokutestapp/登录时,它会将我登录,重定向回来并显示我已登录,但是当我手动刷新时,它会显示我未登录。在Rails 3中,我是否需要做一些特殊的会话处理才能使其在Facebook画布中正常工作?
这是我当前在控制器和视图中拥有的内容。
  def index

  end

  def create
    session['fb_auth'] = request.env['omniauth.auth']
    session['fb_token'] = session['fb_auth']['credentials']['token']
    session['fb_error'] = nil
    redirect_to root_path
  end

  def destroy
    clear_session
    redirect_to root_path
  end

  def failure
    clear_session
    session['fb_error'] = 'In order to use this site you must allow us access to your Facebook data<br />'
    redirect_to root_path
  end

  def clear_session
    session['fb_auth'] = nil
    session['fb_token'] = nil
    session['fb_error'] = nil
  end

索引视图

<div class="container">
    <h1>Heroku FB Test application</h1><br />
    <div class="center"><br />
<%=session[:fb_error]%>     
    <% if session[:fb_token] %>
      <p>
        Successfully logged in.
      </p>
      <a href='logout'>Logout</a>
    <% else %>
        <%= session[:fb_error] %><br />
            <%= link_to "Log in with Facebook", "/auth/facebook",:class => "popup", :"data-width" => 600, :"data-height" => 400 %> <br />
        <p>
            please log in
        </p>
    <% end %>
    </div>
</div>

你使用的是什么浏览器?它会影响到多个浏览器吗? - Jimmy Sawczuk
抱歉,如果您现在无法进行测试。Heroku宕机了 :( - Kevin
你在Heroku上运行了超过1个dyno吗? - mscccc
你解决这个问题了吗? - Purple Hexagon
4个回答

9
你可能遇到的问题是Rails CSRF伪造检测因请求以HTTP POST方法发送而删除了某些身份验证部分。
你的ApplicationController中的第一行可能类似于:
class ApplicationController < ActionController::Base
  protect_from_forgery
  [...]

删除那行'protect_from_forgery',看看是否有助于解决问题。如果是这种情况,请返回并在更有限的范围内设置它(只针对相关控制器,请参见此处的文档:http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html

关于如何让Omniauth工作,这里有一个很好的例子:http://www.communityguides.eu/articles/16,完整的示例代码在https://github.com/markusproske/omniauth_pure上可以找到。其中,他们提供了以下内容:

class ServicesController < ApplicationController
  before_filter :authenticate_user!, :except => [:create, :signin, :signup, :newaccount, :failure]
  protect_from_forgery :except => :create     

你需要使用这两行代码的变体来使omniauth、facebook和rails会话协同工作。如果这对你没有用,请在environment/production.rb中发布你的OmniAuth::Builder信息(隐藏细节),以及你用于身份验证的控制器中的任何其他相关代码,这将有助于调试。
在使用facebook开发rails应用程序时,使用http://tunnlr.com或另一个服务(或仅使用ssh隧道http://blog.kenweiner.com/2007/09/reverse-ssh-tunnel-for-facebook.html)进行调试可能更容易,它非常有助于解决这些问题。

关闭create操作的protect_from_forgery有什么不利影响吗? - oldergod
1
oldergod:不是的。Rails 的 protect_from_forgery 只有在来自 Rails 应用程序内部的表单时才会执行操作。这并不意味着任何特定操作的安全性,只是 Rails 防伪方法没有帮助。 :-) - corprew

1
Facebook中的会话和cookie在iframe中非常难以使用,但并非不可能。在尝试开发每日投票一次的比赛时,我遇到过这种情况。
解决方案是使用P3P标头。老实说,我不太确定它们是如何工作的,但它可以减少跨浏览器cookie在iframe中的问题,特别是IE和Safari。
将以下内容添加到每个页面的顶部:
header('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');

这可能不能完全解决你的问题,但希望它能帮助你找到正确的方向。


这个解决方案只对Internet Explorer真正必要。上述问题似乎在Firefox和Chrome中发生。 - Tim Tisdall
一个P3P头并不是解决方案。这仅适用于Internet Explorer中默认安全配置下的第三方cookie。如果这是第三方cookie问题,需要采取完全不同的方法,而P3P头只会让问题更加混乱。 - Floyd Wilburn

0
如果我使用cookies.permanent.signed[:fb_auth],就可以在Facebook应用程序中返回而无需重新登录。这是绕过iFrames无法工作的会话的最佳方法吗?


0

这听起来像是第三方cookie的问题。如果您只通过Facebook访问网站,您确定使用cookies.permanent.signed是否正常工作?尝试清除cookie,重新启动浏览器,然后转到Facebook画布页面并再次测试。

在Firefox中,尝试转到“工具”->“选项”->“隐私”,查看“接受第三方cookie”是否未选中。如果是,请尝试选中它并再次测试。

第三方cookie可能会导致问题,这一点并不奇怪,令人困惑的是为什么使用持久cookie会有任何区别。

如果您确实验证了第三方cookie是问题所在,那么如果您希望应用程序可供所有人访问,则恐怕没有简单的解决方案。您必须完全停止使用cookie,并仅使用通过GET / POST传递的值来维护会话状态。


通过“仅使用通过GET / POST传递的值维护会话状态”,您是指将自己生成的会话密钥与Canvas应用程序发送/响应的所有请求一起传递吗? - Tomasz Cudziło

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接