当点击某些链接然后友好前进时,强制Omniauth通过弹出窗口登录

ker*_*lin 5 javascript redirect facebook ruby-on-rails omniauth

这个Q&A线程之后,我得到了它,以便用户可以使用弹出窗口通过Omniauth Facebook策略登录.这是我的代码:

视图:

<%= link_to("Sign in with Facebook", "/auth/facebook", :id => "signin", 
:data => {:width => 600, :height => 400}) %>
Run Code Online (Sandbox Code Playgroud)

application.js中:

function popupCenter(url, width, height, name) {
  var left = (screen.width/2)-(width/2);
  var top = (screen.height/2)-(height/2);
  return window.open(url, name, "menubar=no,toolbar=no,status=no,width="+width+",height="+height+",toolbar=no,left="+left+",top="+top);
}

$(document).ready(function() {
  $('a#signin').click(function(e) {
    popupCenter($(this).attr('href'), $(this).attr('data-width'), $(this).attr('data-height'), 'authPopup');
    e.stopPropagation();
    return false;
  });
});
Run Code Online (Sandbox Code Playgroud)

sessions_controller.rb:

  def create
    user = AuthProviders::FacebookUser.find_or_create_user_from(auth_hash)
    session[:current_user_id] = user.id
    @return_to = origin || root_url
    render :callback, :layout => false
  end

  protected

  def auth_hash
    request.env['omniauth.auth']
  end

  def origin
    request.env['omniauth.origin']
  end
Run Code Online (Sandbox Code Playgroud)

意见/会话/ callback.html.erb:

<script type="text/javascript">
  if (window.opener) {
    window.opener.location = '<%= @return_to %>';
  }
  else {
    window.location = '<%= @return_to %>';
  }
  return window.close();
</script>
Run Code Online (Sandbox Code Playgroud)

这很好用,但我需要代码才能处理另外两个场景:

(1)用户点击链接并且控制器操作呈现一个普通的旧HTML响应,但只有当有current_user(即登录)时才能查看该页面.单击链接后,用户将被迫使用弹出窗口通过Facebook登录.经过身份验证后,用户将转发到原始请求页面. 例如,用户单击此链接并且因为他未登录,系统会提示他通过Facebook登录,然后返回到请求的页面:

<%= active_link_to("Your Stuff", user_stuff_path(current_user), :wrap_tag => :li) %>
Run Code Online (Sandbox Code Playgroud)

当你不使用弹出窗口时,使用Hartly的友好转发章节很容易做到这一点.

(2)另一个场景类似于(1),但是控制器动作代替html,呈现javascript,然后打开一个(Twitter引导程序)模态对话框.用户必须登录才能查看此模式框,因此应用程序需要向用户显示Facebook身份验证对话框,然后将他/她转发回模式框.这是我的应用中的示例链接:

<%= link_to(event.home_pick_path, :remote => true, :class => "#{event.home_button_class}", :rel => "tooltip", :data => {:placement => "top", "original-title" => "#{event.home_bet_tooltip}"}) do %>
  <div class="team-name"><%= event.home_team_nickname %></div>
<% end %>
Run Code Online (Sandbox Code Playgroud)

请求URL如下所示:/picks/new?pick_line_id=1&pick_num=1.

因此,无论解决这两种情况的解决方案是什么,都会涉及一些管道,所以我很感激您的时间提前做出回应.

小智 0

我认为你已经过度工程化了。我会采用一种非常简单的方法,但这当然取决于您的业务逻辑。

如果没有当前用户,我会在同一 URL 中呈现带有“登录”按钮的“401”模板,这将触发 Facebook 登录按钮。

在回调中(未测试)..

def create
  if session[:redirect_to].nil?
    session[:redirect_to] = origin
  end
  user = AuthProviders::FacebookUser.find_or_create_user_from(auth_hash)
  session[:current_user_id] = user.id
  unless session[:redirect_to].nil?
    redirect = session[:redirect_to] || root_url
    session[:redirect_to] = nil
    redirect_to redirect
  end 
end
Run Code Online (Sandbox Code Playgroud)

当然,没有模板可以处理它,因为您不需要它。