Zamień omniauth facebook login w wyskakujące okienko

Używam omniauth gem z rails i działa świetnie z logowaniem użytkowników, ale za każdym razem, gdy przenosi Cię na stronę logowania na fb, przekierowuje cię z powrotem. Zastanawiałem się, czy jest sposób, aby zrobić to, co robi większość stron i pokazać FB login w popup, a następnie przeładować rodzic div po zakończeniu. Jakieś pomysły?

Dzięki!

Author: Andrew Marshall, 2010-12-20

4 answers

Pewnie, że możesz.

Według Ciebie:

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

W Twojej aplikacji.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;
});

A następnie w widoku oddzwaniania:

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

Spowoduje to wyświetlenie auth Facebook w wyśrodkowanym wyskakującym okienku 600x400, a następnie, gdy użytkownik powróci z uwierzytelniania, widok zamknie wyskakujące okienko i odświeży Stronę nadrzędną. Rozkłada się wdzięcznie, jeśli użytkownik kliknie ctrl łącze lub nie ma włączonej obsługi Javascript.

 123
Author: Chris Heald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-29 01:00:34

Ok, więc jest problem z rozwiązaniem Chrisa Healda, jeśli używasz OmniAuth w połączeniu z Devise. Problem polega na tym, że po ponownym załadowaniu okna (które znajduje się na stronie logowania) Devise przeniesie Cię do ścieżki root_path, całkowicie ignorując adres URL, do którego próbowałeś uzyskać dostęp i wyświetli komunikat o błędzie "jesteś już zalogowany". Ma to sens, ponieważ Devise chroni zalogowanego użytkownika przed dostępem do strony logowania poprzez przekierowanie na stronę główną. Przeładowując strona logowania natychmiast po zalogowaniu się pojawi się ten problem.

Więc moje rozwiązanie dla kogoś używającego Devise jest następujące:

# 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

Tak więc zwykle, po znalezieniu lub utworzeniu użytkownika za pomocą hasha zwróconego przez określonego dostawcę (Facebook, Twitter itp..), nazywamy funkcję Devise sign_in_and_redirect. Ale nie możemy jeszcze przekierować (pamiętaj, że w tej chwili użytkownik znajduje się w wyskakującym oknie), więc po prostu sign_in użytkownik.

Następnie musimy podać adres url Użytkownik próbował uzyskać dostęp do widoku i możemy uzyskać ten adres url za pomocą metody Devise after_sign_in_path_for.

Wreszcie, musimy renderować widok. Ponieważ będziemy używać widoku tylko do wywoływania JavaScript, nie ma potrzeby renderowania układu, więc wyłączamy go, aby nie spowalniać nas. Oto ten widok:

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

W ten sposób użytkownik jest przekierowywany na właściwy adres url po zalogowaniu i wyświetlana jest prawidłowa wiadomość flash.

Z wyłączonym JavaScript

Po kilku testach I zdałem sobie sprawę, że to rozwiązanie nie pozwala na uwierzytelnianie bez JavaScript, więc chciałbym zrobić dodatek.

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);
}

Zmiana polega na dodaniu prostego parametru o nazwie popup do adresu URL przy użyciu JavaScript. OmniAuth będzie na tyle uprzejmy, aby przechowywać wszelkie paramy zapytań dodane do adresu URL żądania. Więc w końcu sprawdzamy ten param w kontrolerze. Jeśli istnieje, to dlatego, że JavaScript jest włączony:

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

Również, nie zapomnij zrobić tego samego dla swojej failure akcji, która jest wywoływana, gdy użytkownik nie akceptuje logowania.

Nie mógłbym tego zrobić bez rozwiązania Chrisa Healda, więc.. Dziękuję bardzo!
 29
Author: Ashitaka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-28 13:42:31

Publikowanie w przypadku, gdy pomaga innym. Korzystałem z odpowiedzi Chrisa Healda, ale napotkałem problemy z ostatnim bitem javascript zamykającym nowe linki do okien. Na przykład, jeśli opublikowałem link do mojej witryny na Facebook, gdy użytkownicy kliknęli link, nowe okno automatycznie zamknie się w Chrome, ponieważ warunek sprawdza tylko " if (window.otwieracz) "

Rozwiązałem to za pomocą zmiennej globalnej (popupValue). Mogą być bardziej eleganckie rozwiązania, ale pomyślałem, że podzielę się w przypadek, w którym inni trafiają w ten sam problem:

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()
}
});
 4
Author: pejmanjohn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-28 17:59:08

Skończyłem używając Facebook JS SDK, ponieważ jest to łatwiejsze.

# 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

Następnie w Twoich poglądach:

<%= link_to "Sign in with Facebook", "/auth/facebook", id: "sign_in" %>
<%= link_to "Sign out", signout_path, id: "sign_out" %>
To prosto z podpowiedzi Sergio Gutierreza. https://coderwall.com/p/bsfitw
 3
Author: Han,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-20 22:06:35