Jeśli aplikacje REST mają być bezstanowe, jak zarządzasz sesjami?


536

Potrzebuję wyjaśnienia. Czytałem o REST i budowałem aplikacje RESTful. Według wikipedii sam REST jest zdefiniowany jako Reprezentatywny transfer stanu . Dlatego nie rozumiem wszystkich tych bezpaństwowych piskląt, które wszyscy wyrzucają.

Z wikipedii:

W dowolnym momencie klient może przechodzić między stanami aplikacji lub „w spoczynku”. Klient w stanie spoczynku może wchodzić w interakcje z użytkownikiem, ale nie generuje obciążenia i nie zużywa pamięci na klienta na zestawie serwerów lub w sieci.

Czy tylko mówią, że nie używaj magazynu danych na poziomie sesji / aplikacji?

Rozumiem, że jednym z celów REST jest zapewnienie spójnego i dostępnego dostępu URI, na przykład, zamiast ukrywania żądań stronicowania w postach, dzięki czemu numer strony żądania jest częścią GET URI. Dla mnie to ma sens. Ale wygląda na to, że przesadza, mówiąc, że żadne dane na klienta (dane sesji) nigdy nie powinny być przechowywane po stronie serwera.

Co jeśli miałbym kolejkę wiadomości, a mój użytkownik chciał je przeczytać, ale gdy je czytał, chciał zablokować wiadomości nadawców przychodzące na czas jego sesji? Czy nie ma sensu przechowywać tego w miejscu po stronie serwera i pozwolić, aby serwer wysyłał tylko wiadomości (lub identyfikatory wiadomości), które nie zostały zablokowane przez użytkownika?

Czy naprawdę muszę wysyłać całą listę nadawców wiadomości, aby blokować za każdym razem, gdy żądam nowej listy wiadomości? Właściwa dla mnie lista wiadomości nie powinna / nie powinna nawet być publicznie dostępnym zasobem.

Znów próbuję to zrozumieć. Ktoś proszę wyjaśnić.


Aktualizacja:

Znalazłem pytanie o przepełnienie stosu, które ma odpowiedź, która nie do końca mnie prowadzi: jak zarządzać stanem w REST, który mówi, że ważny stan klienta powinien być przesyłany przy każdym żądaniu .... Ugg .. wydaje się dużo narzutów ... Czy to prawda?


2
@ S.Lott: Nie sądzę, by celowo wprowadzało w błąd. Myślę, że to nieporozumienie z powodu mylącej terminologii.
PO PROSTU MOJA poprawna OPINIA

2
@ PO PROSTU MOJA poprawna OPINIA: Ciekawe zgadywanie. Sam nie mogłem w to uwierzyć, ponieważ jest oczywiste, że „bezstanowy” oznacza, że ​​sam protokół REST jest bezpaństwowy; co nie mówi nic o podstawowym stanie aplikacji i aktualizowaniu jej za pomocą żądań PUT, POST i DELETE.
S.Lott,

@ S.Lott: Sam protokół HTTP jest bezstanowy. Z tego, co omówiliśmy poniżej, REST jest poglądem na to, jak zbudować aplikację, nie mając serwera obsługującego stan sesji (w przeciwieństwie do innych rodzajów stanów w rzeczach takich jak DB). I nawet nie myśleć REST był protokół, lecz pogląd na temat korzystania z protokołu HTTP. I pomyślałem wy zdaje się, że to było o tym, jak zbudować swoją aplikację do skali poprzez sklepu po stronie klienta wszystko specyficzny klient danych sesji, a co URI dostęp jako idempotent jak to możliwe, chyba, że nie powinno być. Może nie ... :(
Zak

1
„Może nie…” Co to znaczy? Czy masz nowe pytanie? Wyszukaj go SO. Jeśli tutaj nie ma, to zapytaj.
S.Lott

Czy ktoś czytał w praktyce Webber, Parastatidis i Robinson's ReST (lub w inny sposób widział ich przykład restbucks)? Poniższe odpowiedzi mają sens, ale z pewnością zamówienia na kawę w przykładzie restbucks mówią o kliencie? Liczba zamówień jest skalowana wraz z liczbą klientów. Gdzie przebiega granica między stanem klienta a zasobem?
Rikki,

Odpowiedzi:


339

Bezstanowość oznacza, że ​​każde żądanie HTTP odbywa się w całkowitej izolacji. Gdy klient wysyła żądanie HTTP, zawiera wszystkie informacje niezbędne do spełnienia tego żądania przez serwer. Serwer nigdy nie polega na informacjach z poprzednich żądań. Jeśli ta informacja była ważna, klient musiałby wysłać ją ponownie w kolejnym żądaniu. Bezpaństwowość przynosi także nowe funkcje. Łatwiej jest rozpowszechniać aplikację bezstanową na serwerach z równoważeniem obciążenia. Aplikacja bezstanowa jest również łatwa do buforowania.

Istnieją dwa rodzaje stanów. Stan aplikacji, który żyje na kliencie i stan zasobów, który żyje na serwerze.

Usługa internetowa musi dbać o stan aplikacji tylko wtedy, gdy faktycznie wysyłasz żądanie. Przez resztę czasu nawet nie wie, że istniejesz. Oznacza to, że ilekroć klient wysyła żądanie, musi zawierać wszystkie stany aplikacji, które serwer będzie musiał przetworzyć.

Stan zasobów jest taki sam dla każdego klienta, a jego właściwe miejsce znajduje się na serwerze. Przesyłając zdjęcie na serwer, tworzysz nowy zasób: nowy obraz ma swój własny identyfikator URI i może być celem przyszłych żądań. Możesz pobierać, modyfikować i usuwać ten zasób przez HTTP.

Mam nadzieję, że pomoże to odróżnić bezpaństwowość i różne stany.


4
Czy to oznacza, że ​​za każdym razem, gdy żądanie jest wysyłane, klient powinien wysyłać swojego użytkownika / hasło w celu uwierzytelnienia? Ponieważ myślę, że przechowywanie sesji, nawet jeśli jest na współużytkowanej bazie danych bez sql między wszystkimi serwerami, nie jest bezstanowe, czy też nie?
Carlos Navarro Astiasarán

1
@ CarlosNavarroAstiasarán istnieją różne techniki obsługi uwierzytelniania bezstanowego. Na przykład Google JWT.
geoidesic

1
@geoidesic: „Ponieważ tokeny WWW JSON są bezstanowe, nie ma sposobu, aby je unieważnić bez zapisywania stanu serwera, tym samym pokonując przewagę tokenów bezstanowych”. WIkipedia
ulatekh

@ulatekh To rażące wprowadzenie w błąd co możesz zrobić z tokenami. Przechowywanie zatwierdzonego identyfikatora wraz z tokenem jest bardzo proste i akceptowanie tylko tokenów, które mają zatwierdzony identyfikator jako roszczenie. Bezstanowy nie oznacza, że ​​nie możesz czegoś w bazie danych. Zasadniczo przechowujesz identyfikator w bazie danych, który musi być zgodny z tym samym identyfikatorem w tokenie. Aby odwołać token, usuń identyfikator z bazy danych. Żaden stan nie jest zapamiętywany w samej usłudze. A nawet lepiej, przechowuj klucz podpisu z użytkownikiem w bazie danych i unieważnij klucz.
Andrew T Finnell,

@AndrewTFinnell: Jeśli musisz przechowywać zatwierdzony identyfikator na serwerze, to musi on być przechowywany na wszystkich potencjalnych serwerach, które mogą przetwarzać logowanie REST, co może obejmować wiele stanów serwera w masowo równoległej architekturze serwera WWW.
ulatekh

491

Podstawowe wyjaśnienie to:

Brak stanu sesji klienta na serwerze.

Przez bezstanowy oznacza to, że serwer nie przechowuje żadnego stanu dotyczącego sesji klienta po stronie serwera.

Sesja klient jest przechowywany na kliencie. Serwer jest bezstanowy, co oznacza, że ​​każdy serwer może obsługiwać dowolnego klienta w dowolnym momencie, nie ma koligacji sesji ani sesji lepkich . Odpowiednie informacje o sesji są przechowywane na kliencie i przekazywane w razie potrzeby na serwer.

Nie wyklucza to innych usług, z którymi komunikuje się serwer WWW, utrzymywania stanu obiektów biznesowych, takich jak koszyki, a nie tylko bieżącego stanu aplikacji / sesji klienta.

Stan aplikacji klienta nigdy nie powinien być przechowywany na serwerze, ale przekazywany od klienta do każdego miejsca, które tego potrzebuje.

Że jest gdzie ST w REST pochodzi, Transferu państwa . Przenosisz stan dookoła zamiast przechowywać go na serwerze. Jest to jedyny sposób na skalowanie do milionów jednoczesnych użytkowników. Jeśli nie z innego powodu niż dlatego, że miliony sesji to miliony sesji.

Obciążenie zarządzaniem sesjami jest amortyzowane przez wszystkich klientów, klienci przechowują stan sesji, a serwery mogą obsługiwać wiele zamówień wielkości lub więcej klientów w sposób bezstanowy.

Nawet w przypadku usługi, która Twoim zdaniem będzie potrzebna tylko dziesiątkom tysięcy równoczesnych użytkowników, nadal powinieneś uczynić ją bezpaństwowcem. Dziesiątki tysięcy to wciąż dziesiątki tysięcy i związane będą z tym koszty czasu i przestrzeni.

Bezstanowy to sposób, w jaki protokół HTTP i ogólnie sieć internetowa zostały zaprojektowane do działania i jest ogólnie prostszą implementacją, a zamiast pojedynczej logiki po stronie serwera istnieje jedna ścieżka kodu, aby utrzymać kilka stanów sesji.

Istnieje kilka bardzo podstawowych zasad wdrażania:

Są to zasady, a nie implementacje, sposób ich spełnienia może się różnić.

Podsumowując, pięć kluczowych zasad to:

  1. Nadaj każdej „rzeczy” identyfikator
  2. Połącz rzeczy razem
  3. Użyj standardowych metod
  4. Zasoby z wieloma reprezentacjami
  5. Komunikuj się bezpaństwowo

W rozprawie REST nie ma nic o uwierzytelnieniu lub autoryzacji .

Ponieważ nie ma nic innego niż uwierzytelnienie żądania RESTful od żądania, które nie jest. Uwierzytelnianie nie ma znaczenia dla dyskusji RESTful.

Wyjaśnienie, jak utworzyć aplikację bezstanową dla określonych wymagań, jest zbyt szerokie dla StackOverflow.

Wdrażanie uwierzytelniania i autoryzacji w zakresie REST jest jeszcze bardziej szerokie, a różne podejścia do implementacji są szczegółowo wyjaśnione w Internecie.

Komentarze z prośbą o pomoc / informacje na ten temat powinny / powinny zostać oznaczone jako „ Już nie potrzebne” .


22
Wydaje się to dość odważnym stwierdzeniem, że jest to jedyny sposób na skalowanie do milionów użytkowników. Dlaczego sesje po stronie serwera nie mogą być kolejną usługą?
Zak.

27
@Zak: Ponieważ miliony sesji to miliony sesji. Chodzi o to, aby uniknąć narzutów związanych z zarządzaniem sesjami.
S.Lott,

91
to nie śmiałość, to doświadczenie

21
Nic w mojej odpowiedzi nie sugeruje rozwiązania opartego na dostępie do bazy danych na każde żądanie, jeśli uważasz, że tak, zrozumienie uwierzytelnienia i autoryzacji na taką skalę jest z twojej strony niezadowalające. Uwierzytelnianie może być niejawne w stanie, czy uważasz, że Facebook robi „dostęp do bazy danych” na każde żądanie interfejsu API REST? A może Google? wskazówka: nie

6
Tak więc, jeśli przechowuję stan użytkownika w rozproszonej pamięci podręcznej, powiedzmy memcache, a cały mój serwer sieciowy nie musi teraz przechowywać żadnego stanu, ale przejść do stanu z pamięci podręcznej i uzyskać stan, czy mogę uznać tę aplikację za bezstanową?
Jaskey

76

Czy tylko mówią, że nie używaj magazynu danych na poziomie sesji / aplikacji?

Nie. Nie mówią tego w trywialny sposób.

Mówią, że nie definiuj „sesji”. Nie loguj się. Nie wylogowuj się. Podaj poświadczenia w żądaniu. Każde żądanie jest samodzielne.

Nadal masz magazyny danych. Nadal masz uwierzytelnianie i autoryzację. Po prostu nie marnujesz czasu na ustanawianie sesji i utrzymywanie stanu sesji.

Chodzi o to, że każde żądanie (a) jest całkowicie samodzielne, a (b) może zostać w prosty sposób wyhodowany w gigantycznej farmie serwerów równoległych bez żadnej faktycznej pracy. Apache lub Squid mogą z powodzeniem przekazywać żądania RESTful na ślepo.

Co jeśli miałbym kolejkę wiadomości, a mój użytkownik chciał je przeczytać, ale gdy je czytał, chciał zablokować wiadomości nadawców przychodzące na czas jego sesji?

Jeśli użytkownik chce filtra, wystarczy podać filtr dla każdego żądania.

Czy nie ma sensu ... aby serwer wysyłał tylko wiadomości (lub identyfikatory wiadomości), które nie zostały zablokowane przez użytkownika?

Tak. Podaj filtr w żądaniu RESTful URI.

Czy naprawdę muszę wysyłać całą listę nadawców wiadomości, aby blokować za każdym razem, gdy żądam nowej listy wiadomości?

Tak. Jak duża może być ta „lista nadawców wiadomości do zablokowania”? Krótka lista PK?

Żądanie GET może być bardzo duże. W razie potrzeby możesz wypróbować żądanie POST, nawet jeśli brzmi ono jak rodzaj zapytania.


28
„Nie loguj się. Nie wylogowuj się. Podaj dane uwierzytelniające w żądaniu.” Zawsze widzę takie odpowiedzi w pytaniach o tym, jak pozostać bezstanowym w interfejsie API REST bez żadnych szczegółów na temat tego, gdzie / jak należy przechowywać te poświadczenia na kliencie. Na pewno nie powinniśmy przechowywać nazwy użytkownika i hasła w lokalnej pamięci!
BeniRose

2
@BeniRose nie możemy przechowywać tokena w pamięci lokalnej i używać go w żądaniach, które jednoznacznie identyfikują użytkownika?
Nikhil Sahu

1
Z tego, co rozumiem, Localstorage ma wiele problemów związanych z bezpieczeństwem. Ale jest też wiele innych problemów związanych z sesjami po stronie klienta, takich jak unieważnianie tokenów, wylogowanie użytkownika itp.
BeniRose

3
używasz JWT, które mają podpis, weryfikacja podpisu jest szybka, więc możesz sprawdzić ważność tego stanu.
Archimedes Trajano,

36

Masz całkowitą rację, obsługa całkowicie bezstanowych interakcji z serwerem stanowi dodatkowe obciążenie dla klienta. Jeśli jednak rozważasz skalowanie aplikacji, moc obliczeniowa klientów jest wprost proporcjonalna do liczby klientów. Dlatego skalowanie do dużej liczby klientów jest znacznie bardziej wykonalne.

Gdy tylko nałożysz na serwer odrobinę odpowiedzialności za zarządzanie niektórymi informacjami związanymi z interakcjami konkretnego klienta, obciążenie to może szybko wzrosnąć, aby zużyć serwer.

To jest kompromis.


32

Widok historyczny zarządzania stanem aplikacji użytkownika

Sesje w tradycyjnym sensie utrzymują stan użytkownika w aplikacji wewnątrz serwera. Może to być bieżąca strona w przepływie lub to, co zostało wcześniej wprowadzone, ale nie zostało jeszcze utrwalone w głównej bazie danych.

Powodem tej potrzeby był brak standardów po stronie klienta, aby skutecznie utrzymywać stan bez tworzenia aplikacji lub wtyczek specyficznych dla klienta (tj. Przeglądarki).

Żądanie nagłówka HTML5 i XML z czasem ustandaryzowało pojęcie przechowywania złożonych danych, w tym stanu aplikacji w standardowy sposób po stronie klienta (tj. Przeglądarki) bez konieczności przechodzenia między serwerami.

Ogólne korzystanie z usług REST

Usługi REST są na ogół wywoływane, gdy istnieje transakcja, która musi zostać wykonana lub jeśli trzeba pobrać dane.

Usługi REST mają być wywoływane przez aplikację po stronie klienta, a nie bezpośrednio użytkownika końcowego.

Uwierzytelnianie

W przypadku każdego żądania skierowanego do serwera część żądania powinna zawierać token autoryzacji. Sposób implementacji zależy od aplikacji, ale ogólnie jest to BASICalbo CERTIFICATEforma uwierzytelnienia.

Uwierzytelnianie oparte na formularzu nie jest używane przez usługi REST. Jednak, jak wspomniano powyżej, usługi REST nie mają być wywoływane przez użytkownika, ale przez aplikację. Aplikacja musi zarządzać pobieraniem tokena uwierzytelniającego. W moim przypadku użyłem plików cookie z JASPIC z OAuth 2.0, aby połączyć się z Google w celu uwierzytelnienia i prostego uwierzytelnienia HTTP w celu zautomatyzowanego testowania. Użyłem również uwierzytelniania nagłówka HTTP za pośrednictwem JASPIC do testowania lokalnego (chociaż to samo podejście można wykonać w SiteMinder)

Zgodnie z tymi przykładami uwierzytelnianiem zarządza się po stronie klienta (chociaż SiteMinder lub Google przechowują sesję uwierzytelniania na ich końcu), nic nie można zrobić z tym stanem, ale nie jest to część aplikacji usługi REST.

Żądania pobierania

Żądania pobierania w REST są GEToperacjami, w których żądany jest określony zasób i można go buforować. Sesje serwera nie są potrzebne, ponieważ żądanie zawiera wszystko, co potrzebne do odzyskania danych: uwierzytelnienie i identyfikator URI.

Skrypty transakcyjne

Jak wspomniano powyżej, sama aplikacja po stronie klienta wywołuje usługi REST wraz z uwierzytelnianiem, którym zarządza również po stronie klienta.

Oznacza to, że w przypadku usług REST [jeśli wykonano to poprawnie] to pojedyncze żądanie do serwera REST będzie zawierało wszystko, co jest potrzebne do operacji pojedynczego użytkownika, która robi wszystko, co jest potrzebne w pojedynczej transakcji, wzorzec skryptu transakcji nazywa się.

Odbywa się to POSTzwykle poprzez zapytanie, ale PUTmożna również użyć innych, takich jak .

Wiele wymyślonych przykładów REST (ja to zrobiłem) próbowało podążać za tym, co zostało zdefiniowane w protokole HTTP, po przejściu przez to postanowiłem być bardziej pragmatyczny i pozostawiłem to tylko GET i POST . POSTMetoda nawet nie trzeba zaimplementować wzorzec POST przekierowanie-get.

Niezależnie od tego, jak zauważyłem powyżej, aplikacja po stronie klienta będzie wywoływała usługę i będzie wywoływała POSTżądanie ze wszystkimi danymi, gdy będzie to konieczne (nie za każdym razem). Zapobiega to ciągłym żądaniom do serwera.

Ankieta

Chociaż REST może być również używany do odpytywania, nie polecam go, chyba że będziesz musiał go używać ze względu na kompatybilność przeglądarki. W tym celu użyłbym również WebSockets, dla których zaprojektowałem umowę API . Inną alternatywą dla starszych przeglądarek jest CometD.


27

REST jest bardzo abstrakcyjny. Pomaga mieć dobre, proste przykłady z prawdziwego świata.

Weźmy na przykład wszystkie główne aplikacje społecznościowe - Tumblr, Instagram, Facebook i Twitter. Wszystkie mają zawsze przewijany widok, w którym im bardziej przewijasz w dół, tym więcej treści widzisz, coraz bardziej cofając się w czasie. Wszyscy jednak doświadczyliśmy tego momentu, w którym tracisz miejsce, w którym zostałeś przewinięty, a aplikacja resetuje Cię z powrotem na górę. Na przykład, jeśli zamkniesz aplikację, to kiedy ponownie ją otworzysz, znów będziesz na górze.

Powodem jest to, że serwer nie zapisał stanu sesji. Niestety twoja pozycja przewijania została właśnie zapisana w pamięci RAM na kliencie.

Na szczęście po ponownym połączeniu nie musisz się ponownie logować, ale dzieje się tak tylko dlatego, że nie stracił również ważności zapisany certyfikat logowania po stronie klienta. Usuń i zainstaluj ponownie aplikację, a będziesz musiał zalogować się ponownie, ponieważ serwer nie skojarzył twojego adresu IP z sesją.

Nie masz sesji logowania na serwerze, ponieważ przestrzegają REST.


Teraz powyższe przykłady w ogóle nie obejmują przeglądarki internetowej, ale z tyłu aplikacje komunikują się za pośrednictwem HTTPS z serwerami hosta. Chodzi mi o to, że REST nie musi obejmować plików cookie i przeglądarek itp. Istnieją różne sposoby przechowywania stanu sesji po stronie klienta.

Ale pomówmy przez chwilę o przeglądarkach internetowych, ponieważ przynosi to kolejną ważną zaletę REST, o której nikt tu nie mówi.

Jeśli serwer próbował zapisać stan sesji, w jaki sposób powinien identyfikować każdego klienta?

Nie mógł użyć ich adresu IP, ponieważ wiele osób mogło używać tego samego adresu na współdzielonym routerze. Jak więc?

Nie może używać adresu MAC z wielu powodów, w tym między innymi dlatego, że można zalogować się na wiele różnych kont Facebook jednocześnie w różnych przeglądarkach i aplikacji. Jedna przeglądarka może z łatwością udawać inną, a adresy MAC są równie łatwe do sfałszowania.

Jeśli serwer musi przechowywać jakiś stan po stronie klienta, aby Cię zidentyfikować, musi przechowywać go w pamięci RAM dłużej niż tylko czas potrzebny na przetworzenie twoich żądań lub też musi buforować te dane. Serwery mają ograniczoną ilość pamięci RAM i pamięci podręcznej, nie wspominając o szybkości procesora. Stan po stronie serwera dodaje się do wszystkich trzech, wykładniczo. Ponadto, jeśli serwer będzie przechowywał dowolny stan dotyczący twoich sesji, musi przechowywać go osobno dla każdej przeglądarki i aplikacji, z której jesteś aktualnie zalogowany, a także dla każdego innego urządzenia, którego używasz.


Więc ... Mam nadzieję, że teraz rozumiesz, dlaczego REST jest tak ważny dla skalowalności. Mam nadzieję, że zaczniesz rozumieć, dlaczego stanem sesji po stronie serwera jest skalowalność serwera, czym są przyspawane kowadła do przyspieszenia samochodu.


Ludzie się mylą, myśląc, że „stan” odnosi się do informacji przechowywanych w bazie danych. Nie, odnosi się do wszelkich informacji, które muszą znajdować się w pamięci RAM serwera podczas jego używania.


13

Widzę, że podstawową kwestią tutaj jest pomieszanie sesji z państwem . I chociaż REST określa, że ​​NIE należy przechowywać stanu na serwerze, nic nie stoi na przeszkodzie, aby przechowywać sesję użytkownika .

Zarządzanie stanem na serwerze oznacza, że ​​Twój serwer dokładnie wie, co robi klient (jaką stronę przegląda w której sekcji aplikacji). I nie powinieneś tego robić.

Zgadzam się z innymi osobami, które twierdzą, że powinieneś zachować minimalną wielkość pamięci sesji; i choć jest to zdrowy rozsądek, w rzeczywistości zależy to również od aplikacji. Krótko mówiąc, nadal możesz utrzymywać sesję z buforowanymi danymi, aby obsłużyć żądania przy mniejszym obciążeniu serwera i zarządzać uwierzytelnianiem, zapewniając tymczasowy token uwierzytelnienia / dostępu do użycia przez klienta. Po wygaśnięciu sesji / tokena wygeneruj nową i poproś klienta o jej użycie.

Ktoś może argumentować, że klient powinien lepiej wygenerować token. Mówię, że działa w obie strony i będzie zależeć od aplikacji i tego, kto będzie pracował z interfejsem API.

Właściwe jest również przechowywanie poufnych danych sesji na serwerze. Nie możesz ufać klientowi, że zachowa swój koszyk, który (na przykład) zawiera pole o nazwie „isFreeGift”. Takie informacje powinny być przechowywane na serwerze.

Link wideo podany przez Santanu Deya w jego odpowiedzi jest pomocny. Obejrzyj, jeśli nie masz.

Na marginesie: wydaje się, że wszystkie udzielone już odpowiedzi wydają się pomijać fakt, że niektóre operacje mogą powodować duże obciążenie serwera. Jest to istotne z punktu widzenia zużycia energii, zużycia sprzętu i kosztów (w przypadku serwerów wynajmowanych według cyklu procesora). Dobry programista nie powinien być leniwy w optymalizacji aplikacji, nawet jeśli operację można wykonać bardzo szybko na nowoczesnym procesorze na wynajętym serwerze, za który nie płaci rachunków za prąd i konserwację.

Mimo że pytanie ma kilka lat, mam nadzieję, że moja odpowiedź nadal będzie pomocna.


4
Generalnie zgadzam się z tym sentymentem, ale ostatnio pojawiła się tendencja do twierdzenia, że ​​nawet identyfikator sesji nie powinien być przechowywany na serwerze. Nie dowiedziałem się jeszcze, jakie jest alternatywne rozwiązanie, JWT jest dobrze reklamowane, ale zawiera garść gotchas: cryto.net/~joepie91/blog/2016/06/19/…
BeniRose

11

Bezstanowy oznacza, że ​​stan usługi nie utrzymuje się między kolejnymi żądaniami i odpowiedziami. Każde żądanie zawiera własne poświadczenia użytkownika i jest indywidualnie uwierzytelniane. Ale w stanie stanowym każde żądanie jest znane z każdego wcześniejszego żądania. Wszystkie żądania stanowe są zorientowane na sesję, tj. Każde żądanie musi znać i zachować zmiany wprowadzone w poprzednich żądaniach.

Aplikacja bankowa jest przykładem aplikacji stanowej. Tam, gdzie użytkownik najpierw się loguje, dokonuje transakcji i wylogowuje się. Jeśli po wylogowaniu użytkownik spróbuje dokonać transakcji, nie będzie mógł tego zrobić.

Tak, protokół HTTP jest w zasadzie protokołem bezstanowym, ale aby był on stanowy, tworzymy z plików cookie HTTP. Tak więc domyślnie jest SOAP. Ale może być również stanowy, zależy od używanego frameworka.

HTTP jest bezstanowy, ale nadal możemy utrzymywać sesję w naszej aplikacji Java za pomocą innego mechanizmu śledzenia sesji.

Tak, możemy również utrzymać sesję w usłudze sieciowej, niezależnie od tego, czy jest to REST, czy SOAP. Można to zaimplementować za pomocą dowolnej biblioteki strony trzeciej lub możesz zaimplementować samodzielnie.

Zaczerpnięte z http://gopaldas.org/webservices/soap/webservice-is-stateful-or-stateless-rest-soap


11

Nie ma łyżki.

Nie myśl o bezpaństwowości jak o „ciągłym wysyłaniu wszystkich swoich rzeczy na serwer”. Nie ma mowy. Zawsze będzie stan - sama baza danych jest w pewnym sensie stanem, jesteś zarejestrowanym użytkownikiem, więc każdy zestaw informacji po stronie klienta nie będzie prawidłowy bez strony serwera. Technicznie rzecz biorąc, nigdy nie jesteś naprawdę bezpaństwowcem.

Słowo w debacie dotyczącej logowania za każdym razem

Co to znaczy nawet nie prowadzić sesji i nie logować się za każdym razem? Niektóre oznaczają „wysyłaj hasło za każdym razem”, to po prostu głupie. Niektórzy mówią „nie, oczywiście, że nie, zamiast tego wyślij token ” - oto sesja PHP robi prawie to samo. Wysyła identyfikator sesji, który jest rodzajem tokena i pomaga ci dotrzeć do twoich osobistych rzeczy bez ponownego wysyłania u / pw za każdym razem. Jest również dość niezawodny i dobrze przetestowany. I tak, wygodne, co może zmienić się w wadę, patrz następny akapit.

Zredukuj powierzchnię

To, co powinieneś zrobić , a co ma sens, to zmniejszyć do minimum obciążenie serwera. Języki takie jak PHP sprawiają, że bardzo łatwo jest przechowywać wszystko w pamięci sesji - ale sesje mają swoją cenę. Jeśli masz kilka serwerów WWW, muszą one udostępniać informacje o sesji, ponieważ one również dzielą obciążenie - każdy z nich może być zmuszony do obsługi następnego żądania.

Pamięć współdzielona jest koniecznością. Serwer musi wiedzieć przynajmniej, czy ktoś jest zalogowany czy nie. (A jeśli przeszkadzasz bazie danych za każdym razem, gdy musisz podjąć taką decyzję, jesteś praktycznie skazany). Udostępnione magazyny muszą być znacznie szybsze niż baza danych. To powoduje pokusę: dobrze, mam bardzo szybkie przechowywanie, dlaczego nie zrobić tam wszystkiego? - i tam sprawy potoczą się inaczej.

Więc mówisz, czy przechowujesz sesję na minimalnym poziomie?

Znowu to twoja decyzja. Możesz przechowywać tam rzeczy ze względu na wydajność (baza danych jest prawie zawsze wolniejsza niż Redis), możesz przechowywać informacje nadmiarowo, wdrożyć własne buforowanie, cokolwiek - pamiętaj, że serwery WWW będą miały większe obciążenie, jeśli przechowujesz dużo śmieci na nich. Ponadto, jeśli pękną pod dużym obciążeniem (i będą), tracisz cenne informacje; przy sposobie myślenia REST wszystko, co dzieje się w tym przypadku, to to, że klient ponownie wysyła to samo (!) żądanie i tym razem zostaje obsłużone.

Jak to zrobić w tej chwili?

Nie ma tu jednego uniwersalnego rozwiązania. Powiedziałbym, że wybierz poziom bezpaństwowości i idź z tym. Sesje mogą być kochane przez niektórych i nienawidzone przez innych, ale nigdzie się nie wybierają. Przy każdym żądaniu wysyłaj tyle informacji, ile ma to sens, może trochę więcej; ale nie interpretuj bezpaństwowości jako braku sesji ani logowania za każdym razem. W jakiś sposób serwer musi wiedzieć, że to ty ; Identyfikatory sesji PHP to jeden dobry sposób, tokeny generowane ręcznie to kolejny.

Myśl i decyduj, nie pozwól trendom projektowym myśleć za Ciebie.


1
„Myśl i decyduj, nie pozwól, aby trendy projektowe były dla Ciebie przemyślane”. niestety obecnie bardzo głupio jest po prostu głupio podążać za trendami. Czasami czytając SO dostaniesz te same odpowiedzi tylko ze względu na trend.
10000

Tak, widziałem to na wiele tematów i kiedy zdaję sobie sprawę z tego, co się dzieje, czasami przestaję się kłócić. Wtedy wszyscy szaleli na punkcie tego, jak content-box jest lepszy niż border-box; był to jeden ze sposobów pokazania nienawiści wobec IE. Potem pojawił się bootstrap i nagle wszyscy uwierzyli w granice. Nadchodzą trendy, ale potem znikają. Używaj goto, tabel, iframe, po prostu wiedz, co robisz i dlaczego. Trendści spróbują cię sprowadzić na ziemię, a następnie zarejestrują się i zapłacą na Twojej stronie. Świat znów uratowany.
dkellner,

@dkellner Nie zrozumiałem tej części: „Serwer musi wiedzieć przynajmniej, czy ktoś jest zalogowany, czy nie. (A jeśli przeszkadzasz w bazie danych za każdym razem, gdy musisz o tym zadecydować, jesteś praktycznie skazany).” Załóżmy, że przechowujesz dane sesji w bazie danych za pomocą PHP. Dlaczego zapytanie DB do logowania jest złe (skazanie to mocne słowo), skoro i tak będzie wiele kolejnych żądań DB, aby uzyskać pełne dane użytkownika i inne rzeczy, w oparciu o identyfikator sesji PHP? Innymi słowy, zapytania DB są w każdym przypadku nieuniknione. Ponadto, jeśli nie otrzymasz identyfikatora sesji PHP, wiesz, że użytkownik nie jest uwierzytelniony, nie musisz wysyłać zapytań.
user2923322

Gdy masz tysiące, a nawet miliony użytkowników, nie możesz sobie pozwolić na luksus łączenia się z db za każdym razem, gdy chcesz zachować aktywność, aktualizację lokalizacji, ankietę wiadomości lub cokolwiek, co wymaga krótkiej odprawy. Musisz zaimplementować te wywołania bez (lub z minimalnym) dostępem do bazy danych, dlatego mówię, że może być śmiertelne, jeśli zbudujesz całą koncepcję wokół db. Ponownie mogą wystąpić przypadki, w których dobrze zaprojektowane rozwiązanie db będzie działać, ale typowy programista rozwiąże wszystko, mówiąc „okej, najpierw połączymy się i pobierzemy informacje o użytkowniku”. Praktyka Baaaad.
dkellner


3

Główną różnicą między bezpaństwowcami a stanowymi jest to, że dane są przekazywane z powrotem do serwera za każdym razem. W przypadku bezpaństwowca klient musi podać wszystkie informacje, dlatego w każdym żądaniu może być konieczne przekazanie wielu parametrów. W trybie Stateful cliet przekazuje te parametry jeden raz i są one utrzymywane przez serwer, dopóki klient nie zmodyfikuje ich ponownie.

IMO, API powinien być bezstanowy, co pozwala na bardzo szybkie skalowanie.


2

Musisz zarządzać sesją klienta po stronie klienta. Oznacza to, że musisz wysyłać dane uwierzytelniające przy każdym żądaniu i prawdopodobnie masz, ale nie jest to konieczne, pamięć podręczną na serwerze, która łączy dane uwierzytelniające z informacjami użytkownika, takimi jak tożsamość, uprawnienia itp.

To ograniczenie bezpaństwowości REST jest bardzo ważne. Bez zastosowania tego ograniczenia aplikacja po stronie serwera nie skaluje się dobrze, ponieważ utrzymanie każdej sesji klienta będzie piętą achillesową .


Jeśli wysyłasz dane uwierzytelniające przy każdym żądaniu, gdzie / jak przechowujesz dane uwierzytelniające na kliencie, aby użytkownik nie musiał wprowadzać ich ponownie przy każdym żądaniu?
Amber

1

Gdy tworzysz usługę RESTful, aby się zalogować, musisz uwierzytelnić użytkownika. Możliwą opcją byłoby wysyłanie nazwy użytkownika i hasła za każdym razem, gdy zamierzasz wykonać akcję użytkownika. W takim przypadku serwer w ogóle nie będzie przechowywał danych sesji.

Inną opcją jest wygenerowanie identyfikatora sesji na serwerze i wysłanie go do klienta, dzięki czemu klient będzie mógł wysłać identyfikator sesji na serwer i uwierzytelnić się za jego pomocą. Jest to o wiele bezpieczniejsze niż wysyłanie nazwy użytkownika i hasła za każdym razem, ponieważ jeśli ktoś dostanie te dane, może podszyć się pod użytkownika, dopóki nazwa użytkownika i hasło nie zostaną zmienione. Możesz powiedzieć, że nawet identyfikator sesji może zostać skradziony, a użytkownik zostanie podszyty w tym przypadku i masz rację. Jednak w tym przypadku podszywanie się pod użytkownika będzie możliwe tylko wtedy, gdy identyfikator sesji jest prawidłowy.

Jeśli interfejs API RESTful oczekuje nazwy użytkownika i hasła w celu zmiany nazwy użytkownika i hasła, to nawet jeśli ktoś podszywa się pod użytkownika przy użyciu identyfikatora sesji, haker nie będzie w stanie zablokować rzeczywistego użytkownika.

Identyfikator sesji można wygenerować przez jednokierunkowe blokowanie (szyfrowanie) czegoś, co identyfikuje użytkownika i dodanie czasu do identyfikatora sesji, w ten sposób można określić czas wygaśnięcia sesji.

Serwer może przechowywać identyfikatory sesji lub nie. Oczywiście, jeśli serwer przechowuje identyfikator sesji, naruszyłoby to kryteria zdefiniowane w pytaniu. Ważne jest jednak, aby upewnić się, że identyfikator sesji może zostać zweryfikowany dla danego użytkownika, co nie wymaga przechowywania identyfikatora sesji. Wyobraź sobie sposób, w jaki masz jednokierunkowe szyfrowanie wiadomości e-mail, identyfikatora użytkownika i niektórych prywatnych danych specyficznych dla użytkownika, takich jak ulubiony kolor, byłby to pierwszy poziom i jakoś dodanie daty nazwy użytkownika do zaszyfrowanego ciągu i zastosowanie dwukierunkowego sposób szyfrowania. W rezultacie po odebraniu identyfikatora sesji drugi poziom może zostać odszyfrowany, aby móc określić, którą nazwę użytkownika twierdzi użytkownik i czy czas sesji jest odpowiedni. Jeśli to jest ważne, wtedy pierwszy poziom szyfrowania można zweryfikować, wykonując to szyfrowanie ponownie i sprawdzając, czy pasuje ono do ciągu. Aby to osiągnąć, nie musisz przechowywać danych sesji.


ma to sens
rozpoczęło się

0

Cała koncepcja jest inna ... Nie musisz zarządzać sesjami, jeśli próbujesz zaimplementować protokół RESTFul. W takim przypadku lepiej jest wykonać procedurę uwierzytelnienia przy każdym żądaniu (podczas gdy wiąże się to z dodatkowymi kosztami pod względem wydajności - hashowanie hasła byłoby dobrym przykładem. Nic wielkiego ...). Jeśli korzystasz z sesji - jak możesz rozłożyć obciążenie na wiele serwerów? Założę się, że protokół RESTFul ma na celu całkowitą eliminację sesji - tak naprawdę ich nie potrzebujesz ... Dlatego nazywa się to „bezstanowym”. Sesje są wymagane tylko wtedy, gdy nie można przechowywać niczego innego niż Cookie po stronie klienta po złożeniu żądania (weźmy na przykład starą przeglądarkę nie obsługującą Javascript / HTML5). W przypadku „w pełni funkcjonalnego” klienta RESTFul przechowywanie jest zwykle bezpiecznebase64(login:password) po stronie klienta (w pamięci), dopóki aplikacja nie zostanie załadowana - aplikacja służy do uzyskania dostępu do jedynego hosta, a pliki cookie nie mogą zostać naruszone przez skrypty innych firm ...

Szczególnie polecam wyłączenie uwierzytelniania plików cookie dla usług RESTFul ... sprawdź Autoryzację podstawową / szyfrowaną - powinno to wystarczyć dla usług opartych na RESTFul.


3
Co to jest a client side (in memory) i jak bezpiecznie oszczędzać base64(login:password)po stronie klienta?
RN Kushwaha

1
Nic nie jest zdefiniowane jako „całkowicie bezpieczne”. Można jednak rozważyć użycie protokołu OAuth2 zapewniającego większe bezpieczeństwo niż zapisanie ciągu base64 dla żądania API (uwierzytelnianie podstawowe). Jeśli pozostaniesz przy uwierzytelnianiu podstawowym, możesz użyć protokołu HTTPS w celu zwiększenia bezpieczeństwa.
felixwcf

3
RN Kushwaha, to pytanie, na które nikt nie chce odpowiedzieć, gdy mówi ci, abyś przestał zapisywać sesję na serwerze i przechował ją w kliencie.
BeniRose

0

REST jest bezstanowy i nie utrzymuje żadnych stanów między żądaniami. Pliki cookie / nagłówki klienta są ustawione tak, aby utrzymywać stan użytkownika jak uwierzytelnianie. Powiedzmy, że nazwa użytkownika / hasło klienta są sprawdzane przez mechanizm uwierzytelniania trzeciej części - gerneacja OTP drugiego poziomu itp. Gdy użytkownik zostanie uwierzytelniony - nagłówki / pliki cookie wracają do punktu końcowego usługi odpoczynku, a my możemy przyjąć, że użytkownik jest autoryzowany, ponieważ użytkownik przychodzi z prawidłowymi nagłówkami / plikami cookie . Teraz pewne informacje o użytkowniku, takie jak adres IP, są przechowywane w pamięci podręcznej, a następnie, jeśli przychodzi żądanie z tego samego adresu IP (adres mac) dla wymienionych zasobów, użytkownik może. Pamięć podręczna jest utrzymywana przez określony czas, który zostaje unieważniony po upływie czasu. Można więc użyć albo pamięci podręcznej, albo wpisów DB, aby zachować informacje między żądaniami.


0

Bezstanowy tutaj oznacza, że ​​stan lub metadane żądania nie są utrzymywane po stronie serwera. Utrzymanie każdego żądania lub stanu użytkownika na serwerze doprowadziłoby do wąskich gardeł wydajności. Serwer jest proszony o podanie wymaganych atrybutów do wykonania określonych operacji.

Jeśli chodzi o zarządzanie sesjami lub dostosowywanie użytkowników, wymaga zachowania niektórych metadanych lub stanu prawdopodobnych preferencji użytkownika, historii wcześniejszych żądań. Można to zrobić utrzymując pliki cookie, ukryte atrybuty lub obiekt sesji.

Może to utrzymać lub śledzić stan użytkownika w aplikacji.

Mam nadzieję że to pomoże!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.