Dwuczynnikowe uwierzytelnianie może wydawać się bardzo banalnym procesem ze strony użytkownika. Wiele osób już dawno przyzwyczaiło się do tego, że podczas korzystania z wielu aplikacji nie wystarczy wpisać znanej kombinacji loginu i hasła. Dla zwiększenia bezpieczeństwa i uniemożliwienia nieautoryzowanego dostępu wprowadza się dodatkowy czynnik weryfikacyjny. W większości przypadków jest to unikalny kod, który można otrzymać drogą mailową lub SMS-em.
W tym samouczku dowiemy się, jak można wdrożyć uwierzytelnianie dwuskładnikowe w AppMaster. Jako przykład zostanie wykorzystane wysłanie kodu na pocztę. Przeanalizujemy, jakie moduły należy połączyć, jakie ustawienia wprowadzić, jaki proces biznesowy stworzyć oraz jak sprawdzić gotowy efekt w praktyce.
Najpierw przyjrzyjmy się ogólnemu planowi. Jakie kroki należy zaimplementować w naszym procesie biznesowym?
- Weryfikacja logowania (upewnienie się, że użytkownik faktycznie jest zarejestrowany).
- Sprawdzenie, czy hasło jest poprawne.
- Wysłanie kodu potwierdzającego pocztą lub SMS-em.
- Sprawdzenie przydatności kodu.
- Sprawdzenie poprawności kodu.
- Сompletowanie uwierzytelnienia.
Etap przygotowawczy
Jeszcze przed rozpoczęciem projektowania uwierzytelniania dwuskładnikowego, na etapie rejestracji użytkownika, należy mieć pewność, że:
- Dane użytkownika muszą zawierać e-mail. Zostanie on wykorzystany do wysłania kodu weryfikacyjnego. E-mail jest często wykorzystywany jako login i przyjrzymy się właśnie takiemu przykładowi.
- Login jest unikalny. Dwóch różnych użytkowników z tym samym loginem nie może istnieć w systemie.
Dla ułatwienia rozwiązywania tych (i wielu innych) zadań, moduł Auth moduł jest domyślnie instalowany w każdym projekcie AppMaster. Zawiera on niezbędne modele baz danych, bloki procesów biznesowych oraz punkty końcowe umożliwiające ich wykorzystanie.
Weryfikacja loginu
Login, hasło i kod weryfikacyjny są używane jako parametry wejściowe procesu biznesowego. Jednak na pierwszym etapie potrzebujemy tylko loginu. Pomocne byłoby upewnienie się, że ten użytkownik istnieje. Został zarejestrowany, a informacje o nim są przechowywane w bazie danych.
Aby to zrobić, blok DB: Search User szuka w bazie danych użytkownika o podanym loginie. Pamiętaj, aby ustawić parametr SearchExact = True na szukanie dokładnego dopasowania.
Otrzymane dane przekazywane są do bloku Array Element z indeksem 0 (liczenie rozpoczyna się od zera, a jedyna znaleziona wartość zawsze będzie odpowiadać indeksowi 0 w tablicy).
Blok Is Null sprawdza, czy użytkownik został rzeczywiście znaleziony. I w zależności od wyniku (True/False) If-Else przerwie proces biznesowy z komunikatem o błędzie (Raise Error blok) lub skieruje go dalej.
Sprawdzenie hasła
Na tym etapie należy upewnić się, że hasło użytkownika zostało wprowadzone poprawnie.
I tutaj należy zrozumieć, że hasła nie są przechowywane jawnie w bazie danych. Funkcja Bcrypt haszuje je i tylko wynikowy hasz jest przechowywany w bazie danych. Dlatego nawet jeśli założymy, że dojdzie do wycieku danych, atakujący nadal nie będą w stanie znaleźć haseł użytkowników; są one bezpiecznie zaszyfrowane.
Z tego powodu nie można po prostu uzyskać hasła z bazy danych i porównać go z wprowadzonym hasłem. Musisz uzyskać hash hasła i użyć go do porównania. Aby rozwiązać ten problem, stosuje się Auth: Probe Password stosuje się blok . Jako parametry wejściowe przyjmuje on hasło wprowadzone przez użytkownika (password) oraz hash hasła przechowywany w bazie danych (hashed_password) i konwertuje je na typ danych String (the To String block).
W zależności od wyniku, podobnie jak w poprzednim kroku, korzystając z If-Else wyświetlamy komunikat o błędzie (Raise Error, Message = Password is wrong) lub kierujemy proces do kolejnego etapu.
Rozszerzenie modelu użytkownika
W kolejnym kroku należy dokonać niewielkiej zmiany w modelu użytkownika i dodać informacje o kodzie, który wymaga potwierdzenia.
Ogólnie rzecz biorąc, model User początkowo zawiera pola, które mogą być wykorzystane do tego zadania - Confirmed, Confirmation code, Confirmation code expires at. Jednak w tym przykładzie założymy, że pola te są wykorzystywane tylko do rejestracji i wstępnej weryfikacji konta.
Dla większej przejrzystości procesu stwórzmy osobny model twofa (two-factor authentication), skojarzmy z nim model User (relacja 1 do 1, has one) i dodajmy jedno pole - code ( typString ).
Przygotowanie do wysyłania e-maili
Do wysyłania e-maili z kodami potwierdzającymi należy się wstępnie przygotować. Jedną z najbardziej dostępnych opcji jest wykorzystanie Custom SMTP modułu, który należy zainstalować i skonfigurować.
W przypadku korzystania z Gmail, większość ustawień jest już ustawiona domyślnie, należy dodać nazwę użytkownika i hasło. W przypadku korzystania z innych serwerów pocztowych pomocne będzie odwołanie się do ich dokumentacji w celu uzyskania niezbędnych danych.
W tym przypadku może być konieczna niewielka zmiana ustawień bezpieczeństwa serwera pocztowego. Na przykład Gmail może domyślnie blokować połączenia z wykorzystaniem aplikacji innych firm i trzeba usunąć to ograniczenie w ustawieniach.
Wysyłanie kodu weryfikacyjnego
Sprawdziliśmy login i hasło oraz zakończyliśmy wszystkie niezbędne przygotowania, więc teraz można przystąpić do wysłania listu z kodem potwierdzającym.
Moduł Custom SMTP: Send Email blok wykorzystuje tablicę adresów jako miejsce docelowe. Dlatego nawet jeśli trzeba wysłać list tylko na jeden adres, należy go dodać do tablicy. Do tego celu służy m.in. Append Array wykorzystywany jest blok.
Kolejnym krokiem jest wygenerowanie kodu weryfikacyjnego. Blok Random string blok jest do tego odpowiedni. Wyślemy kod składający się z 6 liczb losowych i dokonamy odpowiednich ustawień. Length = 6, With 0-9 = True, wszystkie pozostałe parametry = False.
Następnie należy stworzyć tekst listu. Aby to zrobić, należy użyć bloku Concat Strings aby dodać tekst wyjaśniający do wygenerowanego kodu (First = Verification code: ), przekonwertować wynik na typ danych Text (To Text blok), i połączyć wynik z body parametrem bloku wysyłającego e-mail.
Do ostatecznego wysłania pozostaje jedynie określenie tematu listu (subject) oraz nadawcy (from_name).
Nie wystarczy jednak tylko wysłać kod; musi on również zostać zapisany w danych użytkownika. Trzeba przecież sprawdzić jego poprawność, gdy użytkownik otrzyma kod i odeśle go jako potwierdzenie.
Aby to zrobić, wykorzystamy model twofa, który przezornie stworzyliśmy wcześniej. Jeśli jest to pierwsze przesłanie kodu, należy utworzyć go z informacją, do jakiego użytkownika należy. W przypadku ponownego użycia należy załatać istniejący wpis, podając jego ID i nowy kod.
Ostatnim krokiem etapu jest wykorzystanie Raise Error do zwrócenia komunikatu o wysłaniu kodu na e-mail.
Sprawdzanie przydatności kodu
Warto zadbać o dodatkowe zabezpieczenie i ochronę kodu przed banalnym wyliczeniem. Najrozsądniej byłoby ograniczyć liczbę prób wejścia, ich częstotliwość oraz czas życia przesłanego kodu. Nie będziemy analizować wszystkich tych przykładów; wymagania dotyczące bezpieczeństwa są indywidualne dla każdego projektu i mogą obejmować wiele różnych warunków. Ograniczamy się do sprawdzenia przydatności kodu pod kątem jego okresu ważności.
Użyjmy Current date & time aby uzyskać aktualny czas. Podłączamy go do parametru B bloku Date & time difference bloku. Użyjemy UpdatedAt pole modelu twofa jako parametr A.
W rezultacie otrzymamy Time span - różnicę pomiędzy dwoma punktami czasowymi. Pozostaje tylko sprawdzić, czy różnica ta przekracza pewną wybraną wartość. W naszym przykładzie jest to 5 minut, które ustawimy jako wartość statyczną B bloku Greater bloku.
Blok If-Else wykorzysta wynik porównania do dalszego prowadzenia procesu. Jeżeli True (różnica przekracza 5 minut), proces powróci do kroku wysyłania listu; użytkownik otrzyma zaktualizowany kod. W przypadku. False (kod jest świeży i aktualny), możliwe będzie przejście do sprawdzenia tego kodu.
Przegląd kodu
Ostatnim etapem uwierzytelniania jest sprawdzenie otrzymanego kodu.
Na stronie Equal blok musi sprawdzić, czy kod przekazany przez użytkownika jest zgodny z kodem zapisanym w modelu twofa powiązanym z użytkownikiem. Jeśli tak nie jest i kod został podany nieprawidłowo (If-Else -> False), to należy wyświetlić komunikat o błędzie (Raise Error, Message = Code is wrong). Jeśli porównanie potwierdzi zgodność, można przejść do ostatniego etapu uwierzytelniania.
W tym celu korzystamy z bloku Auth: Authentication i pobieramy informacje o użytkowniku wraz z jego tokenem autoryzacyjnym. Przekazujemy je do End bloku jako wynik udanego uwierzytelnienia.
Tworzenie punktu końcowego
Proces biznesowy został utworzony, ale nie jest jeszcze dostępny do użytku. Należy stworzyć punkt końcowy, który będzie uruchamiał ten proces biznesowy.
Rozsądnym rozwiązaniem byłoby wykorzystanie domyślnego punktu końcowego uwierzytelniania (POST /Auth). Wystarczy zastąpić jego proces biznesowy i zainstalować ten, który został właśnie utworzony. W ten sposób proste uwierzytelnianie zostanie wyłączone, a zamiast niego zastosowane zostanie uwierzytelnianie dwuskładnikowe.
Publikacja i testowanie
To kończy tworzenie uwierzytelniania dwuskładnikowego. Możesz opublikować wynik i sprawdzić go w działaniu. W tym celu wygodnie jest skorzystać ze strony Swagger, do której dostęp można uzyskać, klikając nazwę planu Deploy w sekcji Project API na przycisku Preview.
Pozostaje tylko znaleźć na liście pożądany punkt końcowy, wprowadzić dane użytkownika i rozpocząć wykonanie przyciskiem Execute. Jeśli podczas testowania zostaną znalezione jakieś błędy, to należy wrócić do procesu biznesowego i wprowadzić niezbędne zmiany.