把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