Multi-Factor Authentication (MFA) to proces, który zwiększa poziom bezpieczeństwa aplikacji, wymagając od użytkowników dostarczenia dwóch lub więcej czynników weryfikacyjnych, aby uzyskać dostęp do zasobów. Dodanie MFA do aplikacji FastAPI, w której użytkownik musi przedstawić zarówno coś, co zna (np. hasło), jak i coś, co posiada (np. urządzenie), stanowi istotny krok w kierunku zapewnienia wyższego poziomu ochrony.
W tej części przedstawimy, jak zaimplementować MFA w aplikacji FastAPI, korzystając z metody opierającej się na jednorazowych hasłach opóźnionych w czasie (TOTP). System ten generuje 6-8 cyfrowy kod, który jest ważny przez krótki okres, zazwyczaj 30 sekund.
Aby rozpocząć, należy upewnić się, że mamy zainstalowane odpowiednie pakiety. Zainstalujemy bibliotekę pyotp, która implementuje algorytmy generowania jednorazowych haseł, w tym TOTP. W tym celu użyjemy poniższego polecenia:
Następnie musimy dostosować naszą tabelę użytkowników w bazie danych, aby przechowywała sekret TOTP, który będzie używany do walidacji generowanego kodu. W tym celu dodajemy nowe pole totp_secret do modelu użytkownika:
Po dodaniu odpowiednich zmian w bazie danych możemy przystąpić do implementacji MFA. Zacznijmy od stworzenia dwóch pomocniczych funkcji, które będą generować sekret TOTP oraz URI TOTP do użycia przez aplikację uwierzytelniającą.
Pierwsza funkcja generuje sekret TOTP:
Druga funkcja generuje URI TOTP, które może być użyte do stworzenia kodu QR w aplikacji uwierzytelniającej:
Następnie możemy zaimplementować punkt końcowy, który umożliwi użytkownikowi aktywację MFA. Punkt ten zwróci URI TOTP, które będzie mogło zostać użyte do wygenerowania kodu QR w aplikacji mobilnej użytkownika:
Po aktywacji MFA, użytkownik może przejść do następnego kroku, czyli weryfikacji kodu TOTP, który zostanie wygenerowany przez aplikację uwierzytelniającą. Implementacja punktu weryfikacji wygląda następująco:
Zanim przejdziemy do końca, upewnijmy się, że odpowiedni router jest dodany do głównej aplikacji FastAPI, a aplikacja jest uruchomiona za pomocą komendy:
Warto zwrócić uwagę na kilka istotnych kwestii, które warto rozważyć przy implementacji MFA:
-
Bezpieczeństwo transmisji: Zawsze należy używać HTTPS, aby zapobiec przechwyceniu kodów TOTP i innych wrażliwych informacji podczas transmisji.
-
Bezpieczne przechowywanie sekretów: Sekrety TOTP nie powinny być przechowywane w sposób niezabezpieczony. W produkcyjnych aplikacjach warto zastosować rozwiązania typu HSM (Hardware Security Module) lub dedykowane usługi do przechowywania kluczy.
-
Regularna rotacja sekretów: Regularna zmiana sekretów TOTP to dobry sposób na zminimalizowanie ryzyka ich kompromitacji. Należy rozważyć implementację mechanizmów automatycznej zmiany sekretu.
-
Używanie aplikacji uwierzytelniających: Zamiast polegać na SMS-ach lub e-mailach do weryfikacji, lepiej jest korzystać z aplikacji uwierzytelniających, takich jak Google Authenticator czy Authy, które zapewniają wyższy poziom bezpieczeństwa.
MFA stanowi solidną barierę ochrony przed nieautoryzowanym dostępem, nawet w przypadku wycieku hasła użytkownika. Poprawna implementacja takich rozwiązań w aplikacji to inwestycja w bezpieczeństwo, która pozwoli na minimalizację ryzyka ataków.
Jak przeprowadzać testy wydajności aplikacji w Pythonie z użyciem Locust?
Testowanie wydajności aplikacji jest kluczowe, by upewnić się, że nasza aplikacja jest w stanie obsłużyć rzeczywiste scenariusze użytkowania, szczególnie w warunkach dużego obciążenia. Dzięki systematycznemu wdrażaniu testów wydajnościowych, analizowaniu wyników i optymalizacji na podstawie uzyskanych danych, możemy znacząco poprawić responsywność, stabilność oraz skalowalność aplikacji. W tym rozdziale przedstawimy podstawy przeprowadzania testów wydajnościowych za pomocą frameworka Locust, który jest oparty na składni Pythona.
Aby przeprowadzić testy wydajności, niezbędna jest działająca aplikacja oraz odpowiedni framework do testowania. W tym przypadku użyjemy Locust, frameworka, który bazuje na Pythonie. Szczegółowe informacje na temat Locust można znaleźć w dokumentacji oficjalnej pod adresem: https://docs.locust.io/en/stable/. Przed rozpoczęciem upewnij się, że masz zainstalowany Locust w swoim środowisku wirtualnym, wykonując polecenie:
Po zainstalowaniu Locust możemy przejść do konfiguracji i uruchomienia instancji Locust w celu przeprowadzenia testu wydajności. W tym celu stworzymy plik locustfile.py w głównym katalogu projektu. Ten plik zdefiniuje zachowanie użytkowników w interakcji z naszą aplikacją, którą będziemy testować.
Minimalny przykład pliku locustfile.py wygląda następująco:
Konfiguracja określa klasę użytkownika, który będzie korzystał z naszego serwisu, a także adres hosta oraz endpoint, który ma zostać przetestowany. Następnie, uruchamiamy nasz serwer FastAPI za pomocą polecenia:
Po uruchomieniu serwera, otwieramy nową instancję terminala i uruchamiamy Locust, wykonując polecenie:
Przechodzimy do przeglądarki i wchodzimy na adres: http://localhost:8089, aby uzyskać dostęp do interfejsu webowego Locust. Interfejs ten jest intuicyjny, dzięki czemu łatwo jest ustawić parametry testu:
-
Liczba równoczesnych użytkowników – określa maksymalną liczbę użytkowników, którzy będą korzystać z aplikacji w tym samym czasie.
-
Wskaźnik wzrostu użytkowników – ustala, jak szybko nowych użytkowników będzie dodawanych w trakcie testu, aby symulować rosnący ruch.
Po skonfigurowaniu parametrów wystarczy kliknąć przycisk Start, aby uruchomić symulację generującą ruch na endpoint /home, zdefiniowany w pliku locustfile.py. Alternatywnie, możemy uruchomić test bez interfejsu webowego, używając polecenia w terminalu:
To polecenie uruchamia Locust w trybie headless, symulując:
-
10 użytkowników równocześnie korzystających z aplikacji,
-
Wzrost liczby użytkowników o 1 osobę na sekundę.
Testy wydajności można także zintegrować z procesem Continuous Integration / Continuous Delivery (CI/CD) przed wdrożeniem aplikacji, lub uwzględnić je w większym procesie testowania. Możliwości są niemal nieograniczone – warto więc zapoznać się ze szczegółową dokumentacją Locust, aby testować każdy aspekt ruchu w aplikacji. W tym rozdziale masz wszystkie narzędzia, by debugować i kompleksowo testować swoją aplikację.
Oprócz powyższych kroków, warto zwrócić uwagę na szereg istotnych kwestii związanych z testowaniem aplikacji pod kątem dużego obciążenia. Warto pamiętać, że testy wydajnościowe są najbardziej efektywne, gdy przeprowadzane są w realistycznych warunkach – na przykład przy symulacji różnorodnych scenariuszy użytkowania, takich jak zwiększony ruch, czy wielokrotne obciążenie serwera. Testy powinny być regularnie powtarzane, by mieć pewność, że aplikacja utrzymuje odpowiednią wydajność również po wprowadzeniu nowych funkcjonalności lub zmian w kodzie.
Ponadto warto również rozważyć zastosowanie różnych narzędzi do monitorowania wydajności, takich jak Prometheus, Grafana czy ELK stack (Elasticsearch, Logstash, Kibana), które pozwolą na dokładniejszą analizę i wizualizację wyników testów wydajnościowych. Testowanie wydajności powinno być integralną częścią procesu tworzenia oprogramowania, ponieważ pozwala na wczesne wykrycie problemów z wydajnością, zanim staną się one krytyczne.
Jak skonfigurować połączenie z bazą danych w FastAPI przy użyciu SQLAlchemy i asyncio?
Współczesne aplikacje webowe często wymagają efektywnego zarządzania bazami danych, zwłaszcza w kontekście używania asynchronicznych metod operacji, które zapewniają lepszą wydajność w przypadku dużych obciążeń. Jednym z najpopularniejszych frameworków do pracy z bazami danych w Pythonie jest SQLAlchemy, który wspiera zarówno tradycyjne, jak i asynchroniczne podejścia do operacji na bazach danych. Integracja FastAPI z SQLAlchemy i asyncio umożliwia tworzenie wydajnych aplikacji webowych. Oto jak skonfigurować takie połączenie krok po kroku.
Proces integracji FastAPI z bazą danych przy użyciu SQLAlchemy, a także asyncio, składa się z kilku etapów. Pierwszym z nich jest stworzenie odpowiednich klas mapujących obiekty na tabele bazy danych. W tym celu tworzymy plik database.py, w którym zdefiniujemy nasze modele bazodanowe. Przykład klasy Ticket, która będzie reprezentować tabelę w bazie danych, może wyglądać następująco:
W tym przykładzie klasa Ticket odpowiada tabeli tickets, której kolumny odpowiadają atrybutom tej klasy. Kolumna id jest kluczem podstawowym, a price, show i user to dane związane z biletami.
Po utworzeniu klas mapujących, kolejnym krokiem jest stworzenie warstwy abstrakcji, która umożliwi komunikację z bazą danych za pomocą SQLAlchemy. Będzie to obejmować utworzenie silnika (engine) oraz sesji (session), które będą służyły do wykonywania operacji na danych. W tym celu tworzymy plik db_connection.py, w którym zdefiniujemy funkcję do uzyskania silnika oraz sesji asynchronicznej:
W tym przypadku używamy bazy danych SQLite i obsługi asynchronicznej poprzez bibliotekę aiosqlite. Dzięki temu, nasze operacje na bazie danych będą wykonywane w sposób asynchroniczny, co pozwala na lepszą obsługę równoczesnych zapytań.
Kolejnym etapem jest zainicjowanie połączenia z bazą danych podczas uruchamiania serwera FastAPI. W tym celu w pliku main.py definiujemy odpowiednią konfigurację serwera oraz akcje wykonywane przy starcie aplikacji. Używamy do tego parametru lifespan w obiekcie FastAPI:
W powyższym kodzie zapewniamy, że przy starcie aplikacji wszystkie brakujące tabele w bazie danych zostaną utworzone, a po zakończeniu działania aplikacji połączenie z bazą zostanie zamknięte.
Po skonfigurowaniu połączenia z bazą danych, możemy przejść do implementacji operacji CRUD (Create, Read, Update, Delete). Operacje te są podstawą interakcji z bazą danych, a ich implementacja w FastAPI jest łatwa i intuicyjna.
Przykładowo, aby dodać nowy bilet do bazy danych, tworzymy odpowiednią funkcję:
Funkcja ta przyjmuje dane nowego biletu, dodaje je do bazy danych i zwraca ID dodanego biletu. Podobnie, możemy zrealizować operacje do pobierania i aktualizowania danych:
Podobne operacje można zaimplementować dla innych operacji CRUD, takich jak usuwanie rekordów czy aktualizowanie innych pól.
Warto dodać, że oprócz używania SQLite, SQLAlchemy wspiera wiele innych baz danych, takich jak MySQL, PostgreSQL czy MariaDB. Wystarczy zmienić odpowiedni ciąg połączenia (SQLALCHEMY_DATABASE_URL) na właściwy dla wybranej bazy danych, np. dla MySQL:
Powyższa zmiana wymaga instalacji odpowiedniego sterownika (aiomysql) w środowisku.
Oczywiście, ważnym aspektem jest również obsługa błędów i zapewnienie, aby operacje na bazie danych były transakcyjne, co pozwala na zapewnienie integralności danych, nawet w przypadku nieoczekiwanych błędów aplikacji. Warto również pamiętać o optymalizacji zapytań, szczególnie w przypadku bardziej skomplikowanych operacji na dużych zbiorach danych.
Jak zintegrować FastAPI z bazą danych MongoDB: Przewodnik po ustawieniu połączenia i operacjach CRUD
Zanim rozpoczniesz pracę z tym przewodnikiem, upewnij się, że masz zainstalowane pakiety Python oraz FastAPI w swoim środowisku. Konieczne jest również posiadanie działającej instancji MongoDB, która będzie osiągalna w twoim systemie. Jeśli jeszcze jej nie masz, możesz skonfigurować lokalną instancję MongoDB, korzystając z oficjalnej dokumentacji, dostępnej pod adresem: https://www.mongodb.com/try/download/community. W naszym przykładzie przyjmiemy, że MongoDB działa na porcie http://localhost:27017, ale jeśli korzystasz z innego portu lub masz instancję na zdalnym serwerze, wystarczy odpowiednio dostosować URL w kodzie.
Aby aplikacja FastAPI mogła komunikować się z MongoDB, musisz zainstalować pakiet motor, który jest asynchronicznym sterownikiem do MongoDB stworzonym przez MongoDB Inc. Instalację możesz przeprowadzić za pomocą polecenia:
pip install motor.
Po zainstalowaniu wymaganych pakietów, możemy przejść do konfiguracji połączenia z MongoDB w naszej aplikacji FastAPI. Pierwszym krokiem jest stworzenie folderu streaming_platform, a w nim podfolderu app, w którym umieścimy plik db_connection.py. Plik ten będzie odpowiedzialny za konfigurację połączenia z MongoDB. W tym pliku definiujemy klienta MongoDB za pomocą AsyncIOMotorClient:
Teraz możemy stworzyć funkcję, która będzie sprawdzać, czy MongoDB jest dostępne. W tym celu używamy logera uvicorn.error, który pozwoli nam śledzić stan połączenia:
Funkcja ping_mongo_db_server sprawdza, czy serwer MongoDB odpowiada na zapytanie. Jeśli serwer nie jest dostępny, wyrzuca błąd, który przerywa dalsze działanie aplikacji.
Kolejnym krokiem jest utworzenie pliku main.py, w którym za pomocą menedżera kontekstu lifespan uruchomimy funkcję ping_mongo_db_server podczas startu aplikacji FastAPI. Wartością lifespan jest zapewnienie, że sprawdzenie połączenia z bazą danych odbędzie się przed pełnym uruchomieniem serwera:
Jak definiować i używać modeli zapytań i odpowiedzi w FastAPI?
FastAPI, dzięki swojej prostocie i elastyczności, oferuje programistom bardzo wygodne narzędzia do definiowania i walidowania danych w aplikacjach webowych. Kluczowym elementem w tym procesie są modele Pydantic, które pozwalają na dokładne określenie struktury danych, zarówno dla zapytań, jak i odpowiedzi. W tej sekcji omówimy, jak tworzyć modele, jak zarządzać danymi w aplikacji oraz jak zapewnić ich poprawność i zgodność ze zdefiniowanymi schematami.
Pierwszym krokiem w pracy z FastAPI jest zdefiniowanie modelu, który będzie odpowiadał na określone zapytania i stanowił bazę do walidacji danych wejściowych. Załóżmy, że tworzymy aplikację do zarządzania książkami. Musimy utworzyć model, który będzie przechowywał informacje o tytule, autorze i roku wydania książki. Oto przykład takiego modelu:
W tym przypadku Book jest klasą pochodzącą od BaseModel, która definiuje trzy atrybuty: tytuł, autora i rok wydania, przy czym każdy z tych atrybutów ma określony typ danych.
W FastAPI modele Pydantic pełnią dwie główne funkcje. Po pierwsze, służą do walidacji danych wejściowych, na przykład gdy użytkownik przesyła dane za pomocą zapytania POST. Po drugie, umożliwiają generowanie odpowiedzi, które są zgodne z określonym schematem. Na przykład, jeśli mamy endpoint do dodawania książek, możemy zdefiniować endpoint, który przyjmie dane w formacie JSON, a FastAPI automatycznie sprawdzi, czy te dane są zgodne z naszym modelem:
W tym przypadku, jeśli użytkownik wyśle zapytanie POST z danymi w formacie JSON, które nie będą spełniały wymagań modelu (np. brakujący tytuł lub nieprawidłowy rok wydania), FastAPI automatycznie zwróci odpowiedź o błędzie. Ta walidacja odbywa się dzięki Pydantic.
Jednak Pydantic oferuje znacznie więcej funkcji walidacji, które umożliwiają dokładniejsze doprecyzowanie, jakie dane mogą zostać przekazane do aplikacji. Przykładem może być dodanie reguł dotyczących długości pól tekstowych czy zakresu liczb:
W tym przykładzie używamy funkcji Field, aby dodać ograniczenia: minimalną i maksymalną długość tytułu i autora oraz zakres lat dla roku wydania książki. Dzięki temu aplikacja jest w stanie odrzucić dane, które nie spełniają tych warunków.
Oczywiście w wielu przypadkach konieczne jest dostosowanie odpowiedzi API do potrzeb klienta. Często chcemy zwrócić tylko część danych lub zmienić format odpowiedzi. FastAPI umożliwia stworzenie modeli odpowiedzi, które precyzyjnie definiują, jakie dane mają zostać zwrócone. Przykład:
Tutaj definiujemy model BookResponse, który zawiera tylko tytuł i autora książki, a w odpowiedzi na zapytanie GET zwracamy listę książek w tym formacie. Dzięki temu klient otrzymuje dane w odpowiedniej postaci, bez zbędnych informacji, jak np. rok wydania.
Modele odpowiedzi są szczególnie przydatne, gdy chcemy w sposób bardziej kontrolowany zarządzać danymi w odpowiedziach API, na przykład ukrywając informacje, które mogą być wrażliwe, lub dostosowując odpowiedź do konkretnego formatu oczekiwanego przez użytkownika.
FastAPI nie ogranicza się jednak tylko do prostych modeli. Można tworzyć bardziej zaawansowane struktury danych, które zawierają zagnieżdżone modele lub nawet listy innych modeli. Pydantic pozwala na tworzenie złożonych schematów danych, które są zarówno łatwe do zdefiniowania, jak i bardzo efektywne pod względem wydajności. Oczywiście, zależnie od wymagań aplikacji, można również definiować domyślne wartości, sprawdzać zakresy, stosować wyrażenia regularne i inne mechanizmy walidacji, które pomagają w jeszcze dokładniejszym zarządzaniu danymi.
Ważnym aspektem w pracy z FastAPI i Pydantic jest również możliwość testowania naszych endpointów. Można to robić za pomocą Swagger UI lub Postman, które automatycznie generują interfejsy pozwalające na łatwe testowanie endpointów. Dzięki nim, wystarczy wprowadzić odpowiednie parametry (np. author_id lub year w zapytaniach GET), aby sprawdzić, czy aplikacja zwraca poprawne odpowiedzi. Testowanie za pomocą tych narzędzi jest szybkie, intuicyjne i pozwala na natychmiastowe wykrywanie błędów w implementacji.
Praca z FastAPI i Pydantic to ogromna zaleta, jeśli chodzi o tworzenie bezpiecznych, szybkich i skalowalnych aplikacji. Dzięki prostocie składni i potężnym funkcjom walidacji oraz zarządzania danymi, programiści mogą szybko budować aplikacje, które nie tylko działają, ale również są zgodne z określonymi normami i zasadami. Modelowanie danych w FastAPI pozwala na utrzymanie porządku i spójności w aplikacji, jednocześnie minimalizując ryzyko wystąpienia błędów związanych z nieprawidłowymi danymi.

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский