Uwierzytelnić użytkownika za pomocą omniauth i Facebook dla rails API?

Buduję API Rails i z powodzeniem zbudowałem sposób uwierzytelniania użytkownika przy użyciu tożsamości Omniauth.

Po prostu wysyłamy do auth / identity / callback od klienta, przekazując auth_key i hasło.
Następnie serwer zwraca token doorkeeper, którego użytkownicy używają od tego czasu, aby uzyskać dostęp do aplikacji i zidentyfikować się.

Ten schemat ilustruje to:

Relacja z serwerem klienta

Chcielibyśmy teraz zaimplementować Facebook login od klienta, ale są problemy z jego działaniem, zarówno teoretycznie, jak i praktycznie.

Na prostej aplikacji Rails z tożsamością Omniauth, po prostu wywołujesz auth / facebook, ale jeśli umieścimy link z tego w kliencie, wywoła on serwer, a następnie loguje Serwer:

INFO -- omniauth: (facebook) Request phase initiated.

Aplikacja jest poprawnie skonfigurowana w Facebook z identyfikatorem i sekretem, więc może monit logowania zostanie zwrócony na serwer?

[1]}zaczynam się mylić, choć łączenie uwierzytelniania. Każda pomoc z wdzięcznością doceniam to!

Tutaj wpisz opis obrazka

Author: idrysdale, 2013-11-15

3 answers

Najlepszy sposób znalazłem (po utknięciu na chwilę w tej sprawie ) jest zrobić omniauth2 (konkretnie w moim przypadku za pomocą satellizer angular plugin) ręcznie...

Omówię rozwiązanie dla Facebook, Jak to było w moim przypadku, ale wszystko może dotyczyć każdego innego dostawcy.

Najpierw musisz wiedzieć, jak działa omniauth2 (Jak udokumentowano dla ludzi tutaj )...

  1. Client: Otwórz wyskakujące okno dla użytkownika / align = "left" /
  2. Client: Zaloguj się (jeśli to konieczne), a następnie Autoryzuj aplikację.
  3. Klient: po pomyślnej autoryzacji wyskakujące okienko jest przekierowywane z powrotem do aplikacji. z code (Kod autoryzacji) parametr ciągu zapytania

adres URL przekierowania musi odpowiadać adresowi URL aplikacji front-end, a nie adresowi URL back-end I musi być określony w konfiguracjach aplikacji facebook

  1. Klient: The code parametr jest wysyłany z powrotem do okna nadrzędnego, które otworzyło wyskakujące okienko.
  2. Client: okno rodzica zamyka wyskakujące okienko i wysyła zapytanie POST do backend/auth/facebook z parametrem code.
  3. Serwer: code (Kod autoryzacji ) jest wymieniany na access token

poniżej opisano szczegółowo, jak wymienić code na access-token od programistów facebook dokumentacja

  1. Serwer: użyj access-token pobranego w kroku 6 aby pobrać informacje o użytkowniku. jak udokumentowane tutaj z ładnymi pomocami wizualnymi .

  2. VOILA masz sobie użytkownika, który możesz połączyć / utworzyć konto / połączyć z innymi dostawcami oauth / itp. ale pamiętaj, że użytkownik może odwołać niektóre uprawnienia (jak E-mail, facebook obsługuje cofanie niektórych uprawnień uprawnienia)...


(dość gadania, Pokaż mi jakiś kod)

Najpierw musisz dodać HTTParty gem do swojego Gemfile

gem 'httparty'  # Makes http fun again (http client)

Dodałemten gist , który zawiera przepływ dla kroku (6, 7 i 8) są to najbardziej problematyczne kroki i nie są udokumentowane prawie nigdzie.

Gist eksportuje 2 główne metody:

Omniauth::Facebook.authenticate(authorization_code)

Który jest używany do uwierzytelniania użytkownika za pomocą facebook i zwraca user_info, long_live_access_token (valid przez 60 dni)

Omniauth::Facebook.deauthorize(access_token)

Który służy do dezautoryzacji / cofnięcia uprawnień access_token i aplikacji na facebook...

Jest to używane do specjalnych wymagań, które mam, gdy użytkownik odwołuje uprawnienia e-mail wymagane na Facebook login... cofamy wszystkie uprawnienia aplikacji... spowoduje to monit użytkownika przy następnym logowaniu, tak jakby był to jego pierwszy login (nie ma potrzeby przechodzenia do aplikacji facebook i ręcznego odwoływania aplikacji)...

Oto jak jest używany w controller

user_info, access_token = Omniauth::Facebook.authenticate(params['code'])
if user_info['email'].blank?
  Omniauth::Facebook.deauthorize(access_token)
end

To jest to... teraz, jeśli jesteś zainteresowany w wewnętrznych realizacji... oto Kod, jak widać w gist. (dodano w celach informacyjnych) Możesz go rozwidlać, edytować i ulepszać.

require 'httparty'

module Omniauth
  class Facebook
    include HTTParty

    # The base uri for facebook graph API
    base_uri 'https://graph.facebook.com/v2.3'

    # Used to authenticate app with facebook user
    # Usage
    #   Omniauth::Facebook.authenticate('authorization_code')
    # Flow
    #   Retrieve access_token from authorization_code
    #   Retrieve User_Info hash from access_token
    def self.authenticate(code)
      provider = self.new
      access_token = provider.get_access_token(code)
      user_info    = provider.get_user_profile(access_token)
      return user_info, access_token
    end

    # Used to revoke the application permissions and login if a user
    # revoked some of the mandatory permissions required by the application
    # like the email
    # Usage
    #    Omniauth::Facebook.deauthorize(access_token)
    # Flow
    #   Send DELETE /me/permissions?access_token=XXX
    def self.deauthorize(access_token)
      options  = { query: { access_token: access_token } }
      response = self.delete('/me/permissions', options)

      # Something went wrong most propably beacuse of the connection.
      unless response.success?
        Rails.logger.error 'Omniauth::Facebook.deauthorize Failed'
        fail Omniauth::ResponseError, 'errors.auth.facebook.deauthorization'
      end
      response.parsed_response
    end

    def get_access_token(code)
      response = self.class.get('/oauth/access_token', query(code))

      # Something went wrong either wrong configuration or connection
      unless response.success?
        Rails.logger.error 'Omniauth::Facebook.get_access_token Failed'
        fail Omniauth::ResponseError, 'errors.auth.facebook.access_token'
      end
      response.parsed_response['access_token']
    end

    def get_user_profile(access_token)
      options = { query: { access_token: access_token } }
      response = self.class.get('/me', options)

      # Something went wrong most propably beacuse of the connection.
      unless response.success?
        Rails.logger.error 'Omniauth::Facebook.get_user_profile Failed'
        fail Omniauth::ResponseError, 'errors.auth.facebook.user_profile'
      end
      response.parsed_response
    end


    private

    # access_token required params
    # https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.3#confirm
    def query(code)
      {
        query: {
          # The authorization_code we want to exchange for the access_token
          code: code,
          # This must match the redirectUrl registerd in the facebook app.
          # You can save it to ENV['WEB_APP_URL'] if you have multiple facebook apps for development and testing
          # so you can support testing app on development and production app on production env.
          redirect_uri: "http://localhost:9000/",
          client_id: ENV['FB_APP_ID'], # Facebook appId
          client_secret: ENV['FB_APP_SECRET'], # Facebook app secret (must not exist on front-end app for security)
        }
      }
    end
  end
end

Oto kolejny NodeJS tutorial implementujący oauth dla instagram który pomógł mi zrozumieć, jak działa oauth2 (dodany dla odniesienia)

 46
Author: a14m,
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
2016-05-06 15:12:48

Aby rozwiązać ten problem najlepszym zasobem, jaki znalazłem, jest przykładowa aplikacja rails w repo satellizer github: https://github.com/sahat/satellizer/tree/master/examples/server/ruby

Twój kod satelitarny wywołuje Kontroler AuthController.metoda authenticate . Ta metoda wykorzystuje klasy modelu oauth dla każdego dostawcy do konwersji otrzymanego kodu na token dostępu. Następnie w Klasa użytkownika możesz pobrać użytkownika, który pasuje do informacji, które otrzymałeś od dostawcy.

Na końcu metoda kontrolera zwraca klientowi token jwt.

W moim przypadku część kontrolera jest nieco inna, ponieważ używam również devise do uwierzytelniania poczty/hasła, ale kopiuję klasy oauth tak, jak jest i działa jak urok.

 1
Author: Seb Cesbron,
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
2016-05-12 06:32:52

Do komunikacji z facebook api. Polecam użycie klejnotu 'omniauth-facebook' . Możesz sklonować ten przykład, aby zrozumieć więcej: https://github.com/ralphos/omniauth-facebook-example

 0
Author: khanh,
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
2015-06-03 21:10:15