Najważniejsze zagadnienia, które musisz znać
5 godz. 53 min · JavaScript · Full-stack i Programowanie
Adam GospodarczykPrzesyłanie oraz transformacja danych to jeden z najważniejszych elementów działania każdej aplikacji. Dobre zrozumienie tego w jaki sposób odbywa się ten proces, daje równocześnie lepsze zrozumienie całej struktury oraz podejmowania decyzji projektowych. W tym kursie znajdziesz lekcje, które pozwolą Ci uporządkować wiedzę na temat protokołu HTTP oraz formatów wymiany danych.
REST oraz GraphQL to nadal nieodłączone zagadnienia tematu wymiany informacji w kontekście aplikacji webowych. Pomimo tego, że ich koncepcje zwykle są bardzo dobrze opisane w różnych źródłach, tak ich wykorzystanie "na produkcji" potrafi sprawić problemy. W szczególności gdy weźmiemy pod uwagę, wyjątki oraz fakt, że nie każda aplikacja będzie wymagać implementacji REST czy GraphQL w 100%. W tym kursie znajdziesz wiele praktycznych wskazówek związanych z pracą z REST API oraz wprowadzenie do pracy z GraphQL.
Niektóre błędy w aplikacji są bardzo pożądane, w szczególności gdy jasno informują użytkownika o tym, co się wydarzyło oraz o tym, co może z tym zrobić. Pomimo tego, że w wielu przypadkach opracowanie komunikatów leży w rękach osoby odpowiedzialnej za copywriting (i/lub ux writing), tak sama implementacja tych komunikatów odbywa się po stronie kodu. Nie rzadko okazuje się, że poprawna i skuteczna walidacja danych oraz obsługa błędów nie jest oczywista w "produkcyjnych" sytuacjach. W tym kursie znajdziesz najczęściej spotykane problemy oraz sposoby ich rozwiązania.
Bazy danych są praktycznie nieodłączną częścią każdej aplikacji. W roli full-stacka prędzej czy później przyjdzie Ci z nimi pracować a nie rzadko nawet projektować oraz rozbudowywać ich struktury. W tym kursie znajdziesz informacje o bazach danych, które pozwolą Ci je zrozumieć oraz od razu poznać użyteczne techniki, które pomogą Ci w pracy z nimi, zarówno na produkcji jak i w środowisku lokalnym czy testowym.
Nie wszystkie informacje w aplikacji są publiczne. Niektóre wprost nie mogą takie być. Z tego powodu niezbędne są sposoby na to aby poznać a potem weryfikować tożsamość użytkownika, by na jej podstawie przydzielać mu dostęp wyłącznie do zasobów, do których odczytywania posiada uprawnienia. Istnieje wiele technik, które umożliwiają zarządzanie dostępem do danych i w tym kursie poznasz najważniejsze z nich. Dowiesz się nie tylko w jaki sposób zabezpieczać dane ale poznasz też najpopularniejsze sposoby na to aby te zabezpieczenia łamać i obchodzić. Mając świadomość takiej możliwości, będziesz w stanie lepiej podejmować decyzje o tym jak projektować dostęp do informacji.
Istnieją problemy charakterystyczne dla niemal każdej aplikacji. W związku z ich powszechnością, istnieje też szereg rozwiązań lub sposobów na to, aby możliwie zredukować ich następstwa. Na przestrzeni lekcji tego kursu zobaczysz wiele przykładów, które pomogą Ci w codziennej pracy a niekiedy nawet, pozwolą uniknąć błędów, których konsekwencje nie zawsze występują natychmiast.
Kurs powstał z myślą o osobach, które chcą rozwijać się w roli full-stack web developera / developerki, przeprowadzając przez najważniejsze zagadnienia z obszaru wymiany, transformacji oraz przechowywania informacji w aplikacji oraz pomiędzy aplikacjami. Jeżeli potrzebujesz zobaczyć szeroką perspektywę tego, w jaki sposób dane przepływają pomiędzy różnymi częściami aplikacji, lub ugruntować swoją wiedzę na ten temat, to ten kurs jest miejscem, którego szukasz.
Proponuję, abyśmy w tej lekcji skupili się
nieco bardziej na mechanizmach autoryzacji oraz uwierzytelnienia użytkowników.
Przejdziemy sobie przez te
najpopularniejsze mechanizmy raz jeszcze, ale tym razem zwrócimy uwagę na szczegóły.
W kolejnych lekcjach przyjrzymy się metodą implementacji.
Jako pierwszy w kolejce jest BASIC.
Jest to metoda, jak sama nazwa wskazuje, bardzo podstawowa, ale jednocześnie dość
wystarczająca w przypadku, gdy potrzebujemy po prostu w najprostszy
możliwy sposób zabezpieczyć dostęp do jakiegoś zasobu.
W takiej sytuacji autoryzacja wygląda tak,
że użytkownik musi podać swój login i hasło lub też po prostu przekazać nagłówek
zawierający frazę basic, która sygnalizuje to, że mamy do czynienia właśnie z basenów
oraz następnie musi podać w formie base64 swój login oraz hasło.
I tutaj warto zaznaczyć, że jak pewnie
wiesz base64 jest mechanizmem, który umożliwia nie do końca szyfrowanie, tylko
po prostu zamiany naszego ciągu znaków na np.
ciąg taki jaki mamy tutaj.
Warto o tym pamiętać, że nie mamy tutaj do czynienia z szyfrowaniem.
Ze względu na to, że po skopiowaniu tego
ciągu znaków mogę po prostu wykonać metodę Base64 do tego, aby w moim schowku
pojawiła się dokładnie fraza, która kryje się pod tym ciągiem znaków.
Zatem z jednej strony trzeba uważać z
takimi skanami ze względu na to, że w momencie gdy zostaną w jakikolwiek sposób
przechwycone, to nie ma najmniejszego problemu, aby podejrzeć ich zawartość.
W każdym razie, gdy przesyłamy taki nagłówek do serwera, jego zawartość jest
tam odczytywane, a następnie porównywane np.
z plikiem DOT i Anwilu lub też innym
miejscem, w którym znajduje się właśnie te login oraz hasło użytkownika.
Zwykle w tym przypadku raczej nie mówimy o
sytuacji, w której mamy konta użytkowników, tylko po prostu jeden login
oraz hasło, które w dość prosty sposób zabezpiecza dostęp do naszych zasobów.
Oczywiście pamiętaj o tym, aby w tej
sytuacji pod żadnym pozorem nie wykorzystywać nie szyfrowanego połączenia.
Za każdym razem, aby zapewnić minimum
bezpieczeństwa, musimy wykorzystać tutaj certyfikat SSL.
I oczywiście na koniec dnia, w momencie, gdy dane przekazane razem w nagłówku
zgadzają się z tym, co zostało zapisane w pliku, otrzymujemy naszą odpowiedź, bądź w
przeciwnym razie status 401 mówiący o tym, że dostępu do zasobu nie mamy.
Następnym i chyba najbardziej popularnym
sposobem uwierzytelnienia połączenia jest wykorzystanie klucza API.
Taki klucz może być przesłany albo w
custom owym nagłówku, w przypadku którego konwersja często wskazuje nam na to, aby
wykorzystać przedrostek x, a następnie epiki, bądź też dowolną inną nazwę.
Czasem spotykamy tutaj nagłówek Auto Dizajn, a jeszcze w innym przypadku taki
klucz API przesyłany jest bezpośrednio za pomocą Query.
W każdym razie, niezależnie od tego, w jaki sposób przekażemy ten klucz API, to
trafia on do serwera, a następnie zostaje wykorzystywany do tego, aby odnaleźć
użytkownika, do którego ten klucz API należy.
Zatem zwykle wygląda to tak, że w bazie
danych albo bezpośrednio przy użytkowniku, albo w jakiejś oddzielnej tabeli
przechowywana jest informacja o kluczach API przypisanych do użytkownika.
Oczywiście to w jaki sposób przechowywane
są te klucze zależy również od sposobu implementacji oraz też od tego, czy np.
do danego klucza API nie ma przypisanych konkretnych grup uprawnień, bądź też np.
termin wygaśnięcia.
W każdym razie niezależnie od tego schemat działania jest następujący.
Użytkownik w momencie, gdy posiada konto w
jakimś serwisie, ma do swojej dyspozycji klucz API.
Taki klucz API może być tylko jeden dla
danego użytkownika, bądź też użytkownik może wygenerować ich kilka.
No i następnie taki użytkownik musi zadbać o to, aby w momencie nawiązywania
połączenia z serwerem identyfikować się właśnie z pomocą klucza API.
Tego rodzaju uwierzytelnienie w porównaniu
do baz AOW jest o tyle ciekawsze, że nie zawiera w sobie żadnych informacji.
Jest to po prostu ciąg znaków, który
został po stronie naszej bazy danych przypisany do użytkownika.
W związku z tym, niezależnie od tego, kto
próbuje go odczytać, tak naprawdę nie ma tutaj żadnej dodatkowej informacji.
Z drugiej jednak strony, w momencie, gdy ktoś taki klucz przejmie,
to może to być w zasadzie co tylko chce z takim kontem użytkownika.
I z tego powodu ważne jest to, aby
przynajmniej w jakiś sposób umożliwić użytkownikowi zablokowanie takiego klucza,
który został narażony na ekspozycję także w temacie kluczy API.
Myślę, że to tyle. Przechodzimy więc dalej do bardzo
popularnego sposobu uwierzytelnienia, czyli tzw.
off 2.0.
W tym przypadku flow samej autoryzacji od
uwierzytelnienia wygląda w taki sposób, że użytkownik przesyła login oraz hasło, a
serwer weryfikuje te dane pod kątem tego czy są poprawne.
W momencie gdy są, to identyfikator użytkownika zostaje zaszyfrowany w token.
Przykładem takiego tokenu może być Jackson Web Token.
Zatem sytuacja wygląda tak, że w momencie gdy wszystko jest tutaj poprawnie, serwer
zwraca taki token do klienta, a klient musi ten token przechować.
Ostatecznie jednak według mnie najlepszym
z możliwych sposobów jest wykorzystanie HTTP only i póki co tutaj jest.
Przez serwer, a następnie dołączany
automatycznie przez przeglądarkę do każdego kolejnego połączenia.
Oczywiście nie jest to norma i nadal w większości przypadków otrzymamy ten token
w formie po prostu odpowiedzi, której zawartość musimy przechować po stronie
klienta, a następnie przesyłać z każdym kolejnym zapytaniem.
W związku z tym, że taki rodzaj komunikacji nie wykorzystuje stanu
Staples, to za każdym razem w momencie, gdy wysyłamy zapytanie z takim tokenem,
serwer posiada specjalny klucz, który weryfikuje poprawność tego tokenu, a
następnie na jego podstawie przydziela nam dostęp do informacji lub też zwraca status
401 informując nas o tym, że token nie jest poprawny.
Co ciekawe, w tym przypadku możemy
wykorzystać jeszcze jeden token i jest to tzw.
token, który służy do tego, aby uzyskiwać access token bez konieczności ponownego
logowania się i podawania hasła przez użytkownika.
Sytuacja zmienia się wtedy w taki sposób,
że w momencie logowania użytkownik otrzymuje access token, którego data
wygaśnięcia jest stosunkowo krótka oraz dłuższy pod kątem ważności Refresh token.
Jeden i drugi przechowywany jest po
stronie klienta i w momencie, gdy Access token wygasa.
W tej flash token wykorzystywany jest do
tego, aby uzyskać nową parę bez konieczności podawania loginu oraz hasła.
A tymczasem ostatnią formą uwierzytelnienia są klasyczne sesje, w
przypadku których użytkownik po prostu loguje się swoim loginem oraz hasłem, a
serwer po zweryfikowaniu tych informacji tworzy tzw.
Session kuki.
Dodatkowo informacje na temat tej sesji
przechowywane są na tym konkretnym serwerze.
Swoją drogą o tym już zdarzyło mi się tutaj mówić.
W każdym razie w momencie, gdy połączenie zostanie poprawnie nawiązane wraz z
odpowiedzią, po stronie przeglądarki zapisywane jest to Session kuki, a
następnie dołączane do każdego kolejnego zapytania.
I tutaj różnica pomiędzy tokenem a sesjami polega na tym, że sesje posiadają stan.
Oznacza to, że dopiero w momencie albo wygaśnięcia sesji, albo w momencie
wylogowania użytkownika sesja traci ważność.
Dodatkowo też mamy tutaj ten element
polegający na tym, że sesja przechowywana jest bezpośrednio na serwerze.
Oznacza to, że jeżeli byśmy łączyli się z jakimś innym serwerem,
to jak pewnie pamiętasz tej informacji o sesji nie byłoby na nim dostępnej.
W związku z tym mielibyśmy tutaj problem z
tym, żeby potwierdzić, że użytkownik wysyłający zapytanie jest faktycznie
użytkownikiem logował się na tym pierwszym serwerze.
Z tego powodu w przypadku bardziej
rozproszonych serwerów zdecydowanie lepiej jest wykorzystać OAuth 2.0.
Zatem to by było na tyle jeżeli chodzi o sposoby uwierzytelnienia połączenia.
I raz jeszcze mamy tutaj BASIC, czyli
przesłanie kodowanych danych logowania za pomocą nagłówka.
Następnie mamy apki, czyli po prostu
unikatowy dla użytkownika ciąg znaków, którego identyfikuje.
I tak naprawdę każdy, kto posiada ten
klucz API może korzystać z zasobów tego użytkownika.
Następnie mamy 2.0, czyli obecnie drugi bardzo często wykorzystywany system
uwierzytelnienia, polegający na wygenerowaniu np.
tokena jw i przekazywaniu go w trakcie komunikacji poprzez http on i kuki.
No i na samym końcu mamy sesję, czyli
najbardziej klasyczny mechanizm uwierzytelnienia połączenia, które zwykle
mogliśmy spotykać w bardziej klasycznych aplikacjach.
Proponuję więc, abyśmy przyjrzeli się
każdemu z tych sposobów, ale już od strony kodu.
Zatem nie pozostaje mi nic innego, jak zaprosić Cię do kolejnej lekcji.