REST API dla strony internetowej korzystającej z Facebooka do uwierzytelniania

86

Mamy witrynę internetową, w której jedynym sposobem na zalogowanie się i uwierzytelnienie w witrynie jest Facebook (nie był to mój wybór). Przy pierwszym logowaniu za pomocą Facebooka konto jest tworzone automatycznie.

Chcemy teraz stworzyć aplikację na iPhone'a dla naszej strony, a także publiczne API, aby inni mogli korzystać z naszych usług.

To pytanie dotyczy sposobu uwierzytelniania w naszej witrynie z poziomu aplikacji / interfejsu API i jest podzielone na 2 części:

  1. Jaki jest prawidłowy sposób obsługi uwierzytelniania REST z interfejsu API do witryny internetowej, która używa tylko protokołu OAuth serwisu Facebook jako metody uwierzytelniania?

Dużo czytałem i badałem na temat standardowych metod uwierzytelniania dla REST API. Nie możemy używać takich metod, jak uwierzytelnianie podstawowe przez HTTPS , ponieważ nie ma poświadczeń dla użytkownika jako takiego. Coś jak to wydaje się tylko do uwierzytelniania aplikacji przy użyciu interfejsu API.

Obecnie najlepszym sposobem, o jakim mogę pomyśleć, jest trafienie / autoryzacja punktu końcowego w naszym API, przekierowanie do Facebooka OAuth, a następnie przekierowanie z powrotem do witryny i udostępnienie `` tokenu '', którego użytkownik API może użyć do uwierzytelnienia kolejnych upraszanie.

  1. W przypadku oficjalnej aplikacji, którą tworzymy, niekoniecznie musielibyśmy używać publicznego API w ten sam sposób. Jaki byłby najlepszy sposób na rozmowę z naszą witryną i uwierzytelnianie użytkowników?

Rozumiem (myślę), jak uwierzytelniać aplikacje innych firm, które używają naszego API, używając kluczy API (publicznych) i tajnych (prywatnych). Jednak jeśli chodzi o uwierzytelnianie użytkownika korzystającego z aplikacji, jestem raczej zdezorientowany, jak się do tego zabrać, skoro jedynym sposobem, w jaki musimy uwierzytelnić użytkownika, jest Facebook.

Czuję, że brakuje mi czegoś bardzo oczywistego lub nie do końca rozumiem, jak powinny działać publiczne interfejsy API REST, więc wszelkie porady i pomoc będą bardzo mile widziane.

Adam
źródło
Mam podobne pytanie na stackoverflow.com/questions/30230482/ ... które mówi o niektórych z nich
JVK

Odpowiedzi:

99

UPDATE: patrz poniżej

Też intensywnie myślałem o tym pytaniu. Nie jest to jeszcze do końca jasne, ale oto trasa, o której myślę. Tworzę REST API i moi użytkownicy uwierzytelniają się tylko za pomocą połączenia z Facebookiem.

KLIENT:

  1. Użyj interfejsu API Facebooka, aby się zalogować i uzyskać kod OAUTH2.
  2. Wymień ten kod na token dostępu.
  3. W każdym wywołaniu mojego niestandardowego interfejsu API będę umieszczać identyfikator użytkownika Facebooka i token dostępu.

W interfejsie API (dla każdej metody wymagającej uwierzytelnienia użytkownika):

  1. Prześlij żądanie do wykresu / me na Facebooku, używając tokena dostępu z góry.
  2. Sprawdź, czy zwrócony identyfikator użytkownika Facebooka jest zgodny z identyfikatorem użytkownika przekazanym do mojego interfejsu API z góry.
  3. Jeśli token dostępu wygasł, wymagana jest dodatkowa komunikacja.

Jeszcze tego nie przetestowałem. Jak to brzmi?

--- Aktualizacja: 27 lipca 2014 r., Aby odpowiedzieć na pytanie ---

Z powyższej giełdy korzystam tylko raz po zalogowaniu. Po ustaleniu, który użytkownik się loguje, tworzę własny token dostępu i ten token jest używany od tego momentu. Więc nowy przepływ wygląda tak ...

KLIENT:

  1. Użyj interfejsu API Facebooka, aby się zalogować i uzyskać kod OAUTH2.
  2. Wymień ten kod na token dostępu.
  3. Poproś o token dostępu z mojego interfejsu API, w tym token Facebooka jako parametr

Na API

  1. Odbierz żądanie tokena dostępu.
  2. Prześlij żądanie do wykresu / me Facebook, używając tokena dostępu do Facebooka
  3. Sprawdź, czy użytkownik Facebooka istnieje i pasuje do użytkownika w mojej bazie danych
  4. Utwórz własny token dostępu, zapisz go i zwróć klientowi, aby mógł być używany od tego momentu
Chris Greenwood
źródło
Hej, to trochę spóźniona odpowiedź, ale wydaje się, że twoje rozwiązanie rozwiązuje problem, który miałem w mojej pierwszej odpowiedzi. Oczywiście musiałbyś używać HTTPS, aby nie wysyłać pary (id, token) przez przewód w postaci zwykłego tekstu. Ale wygląda na to, że powinno działać!
Olivier Lance
Myślę, że dobrze jest zadzwonić do mnie na serwer i wygenerować własny token dostępu, który będzie używany przez klienta mobilnego.
Der_Meister
Odkryłem, że przechowywanie tajemnicy FB w aplikacji mobilnej jest złą praktyką. Porady Facebooka, aby przechowywać je tylko na serwerze. developers.facebook.com/docs/opengraph/using-actions/…
Der_Meister
Jeśli za każdym razem wyślemy user_id i access_token do serwera API (jako parametry post / get). Czy stworzy lukę w zabezpieczeniach, jeśli ktoś będzie w stanie przechwycić połączenie?
Nathan Do
@NathanDo Używaj protokołu HTTPS między swoim klientem a serwerem API i nie powinno być problemu, jeśli ktoś przechwyci połączenie (pomijając luki typu Heartbleed).
DCR
15

To jest moja implementacja przy użyciu JWT (JSON Web Tokens), w zasadzie podobna do zaktualizowanej odpowiedzi Chrisa. Użyłem Facebook JS SDK i JWT.

Oto moja realizacja.

  1. Klient: użyj Facebook JS SDK, aby zalogować się i uzyskać token dostępu.

  2. Klient: zażądaj JWT z mojego interfejsu API, wywołując /verify-access-tokenpunkt końcowy.

  3. MyAPI: odbiera token dostępu, zweryfikuj go, wywołując /mepunkt końcowy interfejsu API Facebooka.

  4. MyAPI: Jeśli token dostępu jest ważny, znajduje użytkownika w bazie danych, loguje użytkownika, jeśli istnieje. Utwórz token JWT z wymaganymi polami jako ładunkiem, ustaw datę wygaśnięcia, podpisz się tajnym kluczem i odeślij do klienta.

  5. Klient: przechowuje token JWT w pamięci lokalnej.

  6. Klient: wysyła token (token JWT z kroku 5) wraz z żądaniem następnego wywołania interfejsu API.

  7. MyAPI: zweryfikuj token tajnym kluczem, jeśli token jest ważny, wymień token na nowy, odeślij go z powrotem do klienta wraz z odpowiedzią API. (Żaden zewnętrzny interfejs API nie wywołuje weryfikacji tokena tutaj) [jeśli token jest nieprawidłowy / wygasł, poproś klienta o ponowne uwierzytelnienie i powtórzenie od 1]

  8. Klient zastępuje przechowywany token nowym i używa go do następnego wywołania API. Po osiągnięciu wygaśnięcia tokenu token wygasa, odwołując dostęp do API.

Każdy żeton jest używany tylko raz.

Przeczytaj więcej odpowiedzi na temat bezpieczeństwa i JWT

Jak bezpieczny jest JWT

Jeśli możesz zdekodować tokeny JWT, w jaki sposób są one bezpieczne?

JSON Web Tokens (JWT) jako tokeny identyfikacji użytkownika i uwierzytelniania

Wszystko jest Vаиітy
źródło
3
Wydaje mi się, że numer 3 raczej powinien być /debug_token, więc możesz sprawdzić, czy token jest rzeczywiście przeznaczony dla Twojej aplikacji.
Peppe LG,
2
Nie żądaj access_tokenw kliencie. Użyj „przepływu pracy kodu”. Przechodzą codedo MyAPI i dokonać kolejnej rundy wycieczkę do Facebook do wymiany codez access_token. Dokładniej wyjaśniono to tutaj: developers.facebook.com/docs/facebook-login/security
omikron
5

Próbuję odpowiedzieć na to samo pytanie i ostatnio dużo czytałem ...

Nie otrzymam „odpowiedzi”, ale sprawy stają się dla mnie trochę jaśniejsze. Czy przeczytałeś komentarze we wspomnianym artykule ? Uważam, że są naprawdę interesujące i pomocne.

W rezultacie, w świetle tego, jak ewoluowały od czasu napisania pierwszego artykułu, oto, co myślę, że zrobię:

  • HTTPS wszędzie - dzięki temu zapomnisz o HMAC, podpisywaniu, nonce, ...

  • Użyj OAuth2:

    • Gdy żądania uwierzytelnienia pochodzą z moich własnych aplikacji / witryny, użyj tej „sztuczki” (lub jej odmiany) opisanej w odpowiedzi na wspomniany wcześniej artykuł .

    • W moim przypadku mam dwa typy użytkowników: tych z klasycznymi danymi logowania / hasła i tych, którzy zarejestrowali się za pomocą Facebook Connect.
      Dlatego udostępniam zwykły formularz logowania z przyciskiem „Zaloguj się przez Facebooka”. Jeśli użytkownik zaloguje się przy użyciu swoich „klasycznych” poświadczeń, wyślę je po prostu do mojego punktu końcowego OAuth2 z rozszerzeniem grant_type=password.
      Myślę, że jeśli zdecyduje się zalogować przez Facebooka, będzie to proces dwuetapowy:

      • Najpierw użyj Facebooka iOS SDK, aby otworzyć FBSession
      • Kiedy to zrobisz i aplikacja odzyska kontrolę, powinien istnieć sposób na uzyskanie identyfikatora Facebooka dla tego użytkownika. Sam wyślę ten identyfikator do mojego punktu końcowego OAuth2 z przyznaniem rozszerzenia rozumianym przez mój serwer jako „używanie identyfikatora użytkownika FB”.

Zwróć uwagę, że nadal intensywnie badam te wszystkie rzeczy, więc może to nie być idealna odpowiedź ... może nawet nie poprawna! Ale myślę, że to byłby dobry punkt wyjścia. Pomysł wykorzystania „nadania rozszerzenia” do uwierzytelniania na Facebooku może wiązać się z koniecznością zarejestrowania go, aby wszystko działało poprawnie? Nie jestem do końca pewien.

Zresztą mam nadzieję, że udało mi się choć trochę pomóc i że przynajmniej może rozpocząć dyskusję o znalezieniu najlepszego rozwiązania tego problemu :)

Aktualizacja
Logowanie na Facebooku nie jest rozwiązaniem, jak wskazano w komentarzach: każdy może wysłać dowolny identyfikator użytkownika i zalogować się jako ten użytkownik w API.

A co z zrobieniem tego w ten sposób:

  • Pokaż formularz logowania z przyciskiem „Logowanie do Facebooka”
  • Jeśli wybrano tę metodę logowania, postępuj podobnie jak Facebook SDK: otwórz stronę internetową z serwera uwierzytelniania, który zainicjuje logowanie na Facebooku.
  • Gdy użytkownik się zaloguje, Facebook użyje adresu URL przekierowania, aby potwierdzić; ustawić ten adres URL na inny punkt końcowy serwera uwierzytelniania (prawdopodobnie z dodatkowym parametrem wskazującym, że wywołanie pochodzi z aplikacji?)
  • Gdy punkt końcowy uwierzytelniania zostanie trafiony, uwierzytelnianie może bezpiecznie zidentyfikować użytkownika, zachować jego identyfikator użytkownika FB / sesję FB i zwrócić token dostępu do aplikacji przy użyciu niestandardowego schematu adresu URL, tak jak zrobiłby to zestaw SDK Facebooka

Wygląda lepiej?

Olivier Lance
źródło
1
Dziękuję za odpowiedź! Myślałem o większości tego, co powiedziałeś, ale głównym zmartwieniem, jakie miałem podczas korzystania z FB iOS SDK, a następnie wysyłania identyfikatora użytkownika Facebooka, było to, że nie byłoby łatwo wysłać dowolny identyfikator, który chcesz, do punktu końcowego API i twierdzić, że jest inny użytkownik? W tym miejscu zwykle utknąłem ...
Adam,
W rzeczy samej! To było głupie z mojej strony, żeby o tym nie myśleć ... Więc rozwiązanie musi jakoś przejść przez twój własny serwer uwierzytelniający ...
Olivier Lance
Zaktualizowałem moją odpowiedź o inny pomysł na rozwiązanie ... ale właśnie zdałem sobie sprawę, że wspomniałeś o tym w swoim pierwotnym pytaniu! W tej chwili nie widzę nic innego ...
Olivier Lance