Zarządzanie tożsamością i dostępem użytkownika, czyli o co chodzi z IDP?
Czym jest tożsamość użytkownika? Z czego wynika potrzeba zarządzania dostępem w firmie? Jak działa tzw. IDP? Odpowiedź na te pytania znajdziesz w artykule.
Witamy ponownie! Dzisiaj jako Innokrea pokażemy Wam jak możecie zrobić własny projekt w Pythonie wykorzystując do tego FastAPI oraz MongoDB. Pokażemy Wam także jak dodać testy i sprawić, żeby wszystko działało poprawnie w Dockerze. Jeśli jesteście ciekawi, to zapraszamy do lektury!
Rest API to jedna z najpopularniejszych architektur typu klient-serwer używanych obecnie w aplikacjach, definiująca to, w jaki sposób zasoby mogą być dostępne w sieci i przesyłane poprzez Internet. Najważniejszymi cechami są: bezstanowość, interfejs dostępny zwykle poprzez protokół HTTP oraz identyfikacja zasobów poprzez URI. Do implementacji REST API używa się frameworków dostępnych w wielu językach takich jak Java (np. Spring), JavaScript (np. express.js) czy Python (np. Django czy FastAPI).
Jeśli chcecie poczytać o tym jakie są najlepsze praktyki w projektowaniu REST API, to zachęcamy do przeczytania poniższego artykułu z bloga stackoverflow.
https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design/
FastAPI jest jednym z najpopularniejszych frameworków napisanym w języku Python. Nie jest to najszybsze dostępne na rynku rozwiązanie, ale jedno z najszybszych w Pythonie. Dzięki prostocie FastAPI zwiększa prędkość wytwarzania oprogramowania oraz zmniejsza możliwość popełnienia błędu przez dewelopera.
Zacznijmy od stworzenia folderu innokrea, a w nim dodatkowego folderu rest, w którym umieścimy nasz projekt.
Rysunek 1 – Utworzenie projektu
Zaczniemy od utworzenia dwóch folderów app oraz tests oraz plików Dockerfile i requirements.dev. Całe rozwiązanie będziemy od razu, nawet podczas rozwoju aplikacji, uruchamiać w środowisku Docker, aby instalacja była prosta dla każdego.
Struktura folderów powinna wyglądać następująco:
Rysunek 2 – Struktura folderów naszego projektu
Zawartość plików Dockerfile powinna wyglądać następująco:
FROM python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
WORKDIR /app
COPY requirements.dev /app/
RUN apt-get update && \
pip install --no-cache-dir -r requirements.dev
COPY ./app /app/
WORKDIR /
EXPOSE 8000
CMD ["uvicorn", "app.app:app", "--host", "0.0.0.0", "--port", "8000","--reload"]
A pliku requirements.dev tak:
annotated-types==0.6.0
pydantic==2.4.2
uvicorn==0.23.2
fastapi==0.103.1
pymongo==4.6.2
pyjwt==2.8.0
passlib==1.7.4
httpx==0.27.0
asyncio==3.4.3
#Testing requirements
pytest==7.1.3
setuptools==69.2.0
mongomock==4.1.2
freezegun==1.4.0
mock==5.1.0
Zawartość pliku app.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/test")
async def test_endpoint():
return {"message": "This is a test endpoint!"}
Teraz, aby uruchomić projekt, stworzymy jeszcze plik docker-compose-dev.yml, który będzie odpowiadał za zbudowanie naszego obrazu. Utworzymy także bind mount, aby dynamicznie przeładowywać kod, zamiast przebudowywać obraz po każdej edycje.
version: "3.9"
services:
rest-service:
build:
context: .
# Dev version of Dockerfile
dockerfile: Dockerfile
container_name: rest-service
restart: always
ports:
- "8000:8000"
volumes:
- ./app:/app
networks:
- network
networks:
network:
Po wykonaniu poniższej komendy powinniśmy zobaczyć w przeglądarce pod adresem localhost:8000/test odpowiedź od FastAPI.
docker-compose -f docker-compose-dev.yml up --build
Rysunek 3 – działająca aplikacja
Dodatkowo, przy edycji kodu, nasza aplikacja powinna się automatycznie przeładować.
Mamy gotowe podstawowe środowisko deweloperskie, ale właściwie jaką aplikację będziemy robić? Spróbujemy uruchomić bazę danych i zrobić prostą aplikację pozwalającą na rejestrację użytkowników i ich logowanie. Na początek zaproponujemy warstwową architekturę aplikacji tak, aby rozdzielić odpowiedzialność aplikacji na kilka sekcji związanych z obsługą żądania, logiki biznesowej czy danych.
Rysunek 4 – Architektura warstwowa naszej aplikacji, źródło [1]
Utwórzmy strukturę folderów, która pomoże nam w zbudowaniu tej architektury warstwowej. Będziemy mieli następujący podział:
Rysunek 5 – Podział folderów w naszej aplikacji
Przejdźmy teraz do stworzenia bazy danych, której będziemy używać do zapisania użytkowników. W tym celu znowu użyjemy Dockera i bazy danych mongodb oraz biblioteki pymongo.
Dodajmy więc następujący skrypt inicjalizujący bazę danych do folderu ‘rest’ o nazwie db-init.js.
db = db.getSiblingDB("db");
db.createCollection("users");
db.users.insertMany([{
email: "aaa@aaa.com",
role: "user",
password_hash: "9c520caf74cff9b9a891be3694b20b3586ceb17f2891ceb1d098709c1e0969a3",
},{
email: "bbb@bbb.com",
role: "user",
password_hash: "77cd27bc3de668c18ed6be5f5c2909ffdacdf67705c30d132003ad5a89085deb",
},]);
Hasło dla każdego z użytkowników jest takie samo jak login. Następnie wklejmy zmodyfikowany plik docker-compose-dev.yml który dodaje bazę danych na porcie 27017 oraz panel administracyjny do tej bazy na porcie 8080. Dodaliśmy także niezbędne dla projektu zmienne środowiskowe.
version: "3.9"
services:
rest-service:
build:
context: .
# Dev version of Dockerfile
dockerfile: Dockerfile
container_name: rest-service
restart: always
environment:
- WATCHFILES_FORCE_POLLING=true
- DB_HOSTNAME=db
- DB_USERNAME=root
- DB_PASSWORD=root
- DB_PORT=27017
- DB_NAME=db
# JWT CONF
- JWT_TOKEN_ALG=HS256
- JWT_REFRESH_TOKEN_SECRET_KEY=refreshsecret
- JWT_ACCESS_TOKEN_SECRET_KEY=accesssecret
- JWT_ACCESS_TOKEN_EXPIRE_MINUTES=10080
- JWT_REFRESH_TOKEN_EXPIRE_MINUTES=30
ports:
- "8000:8000"
volumes:
- ./app:/app
networks:
- network
db:
image: bitnami/mongodb:7.0.7-debian-12-r0
container_name: db
restart: always
environment:
- MONGODB_REPLICA_SET_MODE=primary
- MONGODB_REPLICA_SET_KEY=123456
- ALLOW_EMPTY_PASSWORD=yes
- MONGODB_ROOT_USER=root
- MONGODB_ROOT_PASSWORD=root
healthcheck:
test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/db --quiet
interval: 10s
timeout: 10s
retries: 3
start_period: 20s
volumes:
- ./db-init.js:/docker-entrypoint-initdb.d/initialize.js
networks:
- network
adminpanel-db:
image: mongo-express:1.0.2-20-alpine3.19
container_name: adminpanel-db
restart: always
depends_on:
- db
ports:
- "8080:8081"
environment:
- ME_CONFIG_MONGODB_SERVER=db
- ME_CONFIG_MONGODB_URL=mongodb://root:root@db:27017/
- ME_CONFIG_MONGODB_AUTH_USERNAME=root
- ME_CONFIG_MONGODB_AUTH_PASSWORD=root
- ME_CONFIG_MONGODB_PORT=27017
# to login to panel use: admin/pass
networks:
- network
networks:
network:
Teraz spróbujmy ponownie uruchomić naszą aplikację z użyciem docker-compose-dev.yml i komend:
docker-compose -f docker-compose-dev.yml down
docker-compose -f docker-compose-dev.yml up --build
Powinniśmy być w stanie zobaczyć zainicjalizowaną kolekcję na localhost:8080 (admin/pass aby się zalogować).
Rysunek 6 – Widok zainicjalizowanej kolekcji w panelu administratora
Dzisiaj udało nam się stworzyć podstawową konfigurację naszego środowiska złożonego z FastAPI, bazy danych i panelu administratora. Za tydzień spróbujemy rozwinąć naszą aplikację i wypełnić stworzone foldery plikami z kodem. Do zobaczenia!
[1] https://dev.to/blindkai/backend-layered-architecture-514h
Zarządzanie tożsamością i dostępem użytkownika, czyli o co chodzi z IDP?
Czym jest tożsamość użytkownika? Z czego wynika potrzeba zarządzania dostępem w firmie? Jak działa tzw. IDP? Odpowiedź na te pytania znajdziesz w artykule.
Bezpieczeństwo
Hej, hej... Programisto, to kolejny artykuł dla Ciebie! Druga część artykułu na temat wzorców projektowych. Poznaj Adapter oraz Memento.
Programowanie
Programisto, to artykuł dla Ciebie! Łap garść przydatnych informacji na temat wzorców projektowych.
Programowanie