把omniauth facebooklogin成一个popup窗口

我正在使用带有rails的omniauth gem,它在login用户方面效果很好,但是每次它都会将您带到fblogin页面,然后将您redirect回来。 我想知道是否有办法做大多数页面,并在popup窗口中显示fblogin,然后重新加载一次完成的父div。 有任何想法吗?

谢谢!

当然,你可以很容易。

在你看来:

 =link_to "Log in with Facebook", omniauth_authorize_path(:user, :facebook), :class => "popup", :"data-width" => 600, :"data-height" => 400 

在你的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); } $("a.popup").click(function(e) { popupCenter($(this).attr("href"), $(this).attr("data-width"), $(this).attr("data-height"), "authPopup"); e.stopPropagation(); return false; }); 

然后在你的callback视图中:

 :javascript if(window.opener) { window.opener.location.reload(true); window.close() } 

这将popup一个中心的600x400popup窗口的Facebookvalidation,然后当用户从身份validation返回时,视图将closurespopup窗口并刷新父页面。 如果用户按住Ctrl键并单击链接,或者没有启用Javascript,则会优雅地降级。

好的,如果您将OmniAuth与Devise结合使用,那么Chris Heald的解决scheme存在问题。 问题是,当您重新加载窗口(即在login页面上),devise会带你到root_path,完全忽略你试图访问的url,并会产生错误消息“你已经login”。 这是有道理的,因为Devise保护login的用户通过redirect到主页来访问login页面。 通过login后立即重新加载login页面,您将最终遇到这个问题。

所以我使用Devise的解决scheme如下:

 # add this wherever needed in your_authentications_or_callbacks_controller.rb sign_in user @after_sign_in_url = after_sign_in_path_for(user) render 'callback', :layout => false 

所以通常情况下,使用由某个提供商(Facebook,Twitter等)返回的散列来查找或创build用户后,我们会调用devise函数sign_in_and_redirect 。 但是我们现在还不能redirect(现在请记住,用户目前处于一个popup窗口中),所以我们只是在用户sign_in

接下来,我们需要传递用户试图访问视图的url,并且我们可以使用Devise的方法after_sign_in_path_for获取该URL。

最后,我们需要渲染视图。 由于我们只会使用视图来调用一些JavaScript,所以不需要渲染布局,所以我们把它关掉不会放慢速度。 这是这个观点:

 # views/your_authentications_or_callbacks/callback.html.erb <script type="text/javascript"> window.opener.location = '<%= @after_sign_in_url %>'; window.close(); </script> 

这样,用户在login后被redirect到正确的URL,并显示正确的Flash消息。

禁用JavaScript

经过一些testing,我意识到这个解决scheme不允许没有JavaScript的authentication,所以我想做一个附录。

 function popupCenter(linkUrl, width, height, name) { var separator = (linkUrl.indexOf('?') !== -1) ? '&' : '?', url = linkUrl + separator + 'popup=true', left = (screen.width - width) / 2, top = (screen.height - height) / 2, windowFeatures = 'menubar=no,toolbar=no,status=no,width=' + width + ',height=' + height + ',left=' + left + ',top=' + top; return window.open(url, name, windowFeatures); } 

这里的变化是使用JavaScript添加一个简单的参数称为popup到URL。 OmniAuth会友好地存储添加到请求url的任何查询参数。 所以最后我们检查控制器中的这个参数。 如果存在,那是因为启用了JavaScript:

 if request.env['omniauth.params']['popup'] render 'callback', :layout => false else redirect_to @after_sign_in_url end 

另外,不要忘记为你的failure行为做同样的事情,当用户不接受login时会被调用。

如果没有Chris Heald的解决scheme,我无法做到这一点,所以..非常感谢!

张贴以防别人帮忙。 我正在使用克里斯Heald的答案,但遇到了麻烦最后一点的JavaScriptclosures任何新的窗口链接。 例如,如果我在Facebook上发布了一个到我的网站的链接,当用户点击链接时,新窗口会自动closures,因为条件只检查“if(window.opener)”

我结束了解决这个使用全局variables(popupValue)。 可能会有更优雅的解决scheme,但我认为我会分享以防其他人遇到同样的问题:

 function popupCenter(url, width, height, name) { var left = (screen.width/2)-(width/2); var top = (screen.height/2)-(height/2); popupValue = "on"; 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.popup").click(function(e) { popupCenter($(this).attr("href"), $(this).attr("data-width"), $(this).attr("data-height"), "authPopup"); e.stopPropagation(); return false; }); if(window.opener && window.opener.popupValue === 'on') { delete window.opener.popupValue; window.opener.location.reload(true); window.close() } }); 

我使用Facebook的JS SDK结束了,因为它更容易。

 # In facebook.js.coffee jQuery -> $('body').prepend('<div id="fb-root"></div>') $.ajax url: "#{window.location.protocol}//connect.facebook.net/en_US/all.js" dataType: 'script' cache: true window.fbAsyncInit = -> FB.init(appId: 'YOUR-APP-ID', cookie: true) $('#sign_in').click (e) -> e.preventDefault() FB.login (response) -> window.location = '/auth/facebook/callback' if response.authResponse $('#sign_out').click (e) -> FB.getLoginStatus (response) -> FB.logout() if response.authResponse true 

然后在你的看法:

 <%= link_to "Sign in with Facebook", "/auth/facebook", id: "sign_in" %> <%= link_to "Sign out", signout_path, id: "sign_out" %> 

这直接来自Sergio Gutierrez的小费 – https://coderwall.com/p/bsfitw