From 92380d4406269ad551477ec4f67bc13f5a6aab85 Mon Sep 17 00:00:00 2001 From: Artem Litvinov Date: Fri, 29 Sep 2023 18:11:11 +0100 Subject: [PATCH] fix: token (token model TBU) --- src/fastapi_app/.env.example | 1 + .../lib/api/v1/schemas/__init__.py | 3 +-- src/fastapi_app/lib/api/v1/schemas/base.py | 7 ----- .../lib/api/v1/services/__init__.py | 0 src/fastapi_app/lib/api/v1/services/token.py | 26 ------------------- .../lib/app/split_settings/project.py | 5 +++- src/fastapi_app/lib/models/__init__.py | 3 ++- src/fastapi_app/lib/models/token.py | 9 +++++++ src/fastapi_app/lib/utils/token.py | 25 ++++++++++++++++++ 9 files changed, 42 insertions(+), 37 deletions(-) delete mode 100644 src/fastapi_app/lib/api/v1/services/__init__.py delete mode 100644 src/fastapi_app/lib/api/v1/services/token.py create mode 100644 src/fastapi_app/lib/models/token.py create mode 100644 src/fastapi_app/lib/utils/token.py diff --git a/src/fastapi_app/.env.example b/src/fastapi_app/.env.example index bbb9717..23e920f 100644 --- a/src/fastapi_app/.env.example +++ b/src/fastapi_app/.env.example @@ -10,5 +10,6 @@ API_HOST=0.0.0.0 API_PORT=8000 JWT_SECRET_KEY=v9LctjUWwol4XbvczPiLFMDtZ8aal7mm +JWT_ALGORITHM=HS256 APP_RELOAD=True diff --git a/src/fastapi_app/lib/api/v1/schemas/__init__.py b/src/fastapi_app/lib/api/v1/schemas/__init__.py index 06d8e5f..3a43b09 100644 --- a/src/fastapi_app/lib/api/v1/schemas/__init__.py +++ b/src/fastapi_app/lib/api/v1/schemas/__init__.py @@ -1,6 +1,5 @@ -from .base import * +from .base import HealthResponseModel __all__ = [ "HealthResponseModel", - "TokenResponseModel", ] diff --git a/src/fastapi_app/lib/api/v1/schemas/base.py b/src/fastapi_app/lib/api/v1/schemas/base.py index 3de6237..5b379ed 100644 --- a/src/fastapi_app/lib/api/v1/schemas/base.py +++ b/src/fastapi_app/lib/api/v1/schemas/base.py @@ -1,12 +1,5 @@ -import uuid - import pydantic -class TokenResponseModel(pydantic.BaseModel): - sub: uuid.UUID - exp: int | None = None - - class HealthResponseModel(pydantic.BaseModel): status: str = pydantic.Field(default=..., examples=["healthy"], description="Схема доступности сервиса") diff --git a/src/fastapi_app/lib/api/v1/services/__init__.py b/src/fastapi_app/lib/api/v1/services/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/fastapi_app/lib/api/v1/services/token.py b/src/fastapi_app/lib/api/v1/services/token.py deleted file mode 100644 index c18b5f2..0000000 --- a/src/fastapi_app/lib/api/v1/services/token.py +++ /dev/null @@ -1,26 +0,0 @@ -import fastapi -from jose import JWTError, jwt -from pydantic import ValidationError - -import lib.app.settings as app_settings -from lib.api.v1 import schemas as app_schemas - -app = fastapi.FastAPI() -settings = app_settings.settings - -security = fastapi.security.HTTPBearer() - - -def get_token_data( - authorization: fastapi.security.HTTPAuthorizationCredentials = fastapi.Security(security), -) -> app_schemas.entity.Token: - token = authorization.credentials - try: - secret_key = settings.project.jwt_secret_key - payload = jwt.decode(token, secret_key, algorithms=["HS256"]) - return app_schemas.entity.Token(**payload) - except (JWTError, ValidationError): - raise fastapi.HTTPException( - status_code=fastapi.status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - ) diff --git a/src/fastapi_app/lib/app/split_settings/project.py b/src/fastapi_app/lib/app/split_settings/project.py index 6102809..cdfdb05 100644 --- a/src/fastapi_app/lib/app/split_settings/project.py +++ b/src/fastapi_app/lib/app/split_settings/project.py @@ -5,6 +5,8 @@ import lib.app.split_settings.utils as app_split_settings_utils class ProjectSettings(pydantic_settings.BaseSettings): + """Project settings.""" + model_config = pydantic_settings.SettingsConfigDict( env_file=app_split_settings_utils.ENV_PATH, env_file_encoding="utf-8", @@ -12,7 +14,8 @@ class ProjectSettings(pydantic_settings.BaseSettings): ) debug: str = "false" - jwt_secret_key: pydantic.SecretStr = pydantic.Field(default=..., validation_alias="jwt_secret_key") + jwt_secret_key: str = pydantic.Field(default=..., validation_alias="jwt_secret_key") + jwt_algorithm: str = "HS256" @pydantic.field_validator("debug") def validate_debug(cls, v: str) -> bool: diff --git a/src/fastapi_app/lib/models/__init__.py b/src/fastapi_app/lib/models/__init__.py index 130e2e2..719ce04 100644 --- a/src/fastapi_app/lib/models/__init__.py +++ b/src/fastapi_app/lib/models/__init__.py @@ -1,3 +1,4 @@ from .base_sqlalchemy import Base +from .token import Token -__all__ = ["Base"] +__all__ = ["Base", "Token"] diff --git a/src/fastapi_app/lib/models/token.py b/src/fastapi_app/lib/models/token.py new file mode 100644 index 0000000..71008e1 --- /dev/null +++ b/src/fastapi_app/lib/models/token.py @@ -0,0 +1,9 @@ +import uuid + +import pydantic + + +# TODO: TBU +class Token(pydantic.BaseModel): + sub: uuid.UUID + exp: int | None = None diff --git a/src/fastapi_app/lib/utils/token.py b/src/fastapi_app/lib/utils/token.py new file mode 100644 index 0000000..d7ab3ef --- /dev/null +++ b/src/fastapi_app/lib/utils/token.py @@ -0,0 +1,25 @@ +import fastapi +import fastapi.security +import jose +import jose.jwt +import pydantic + +import lib.app.settings as app_settings +import lib.models as models + + +def get_token_data( + authorization: fastapi.security.HTTPAuthorizationCredentials = fastapi.Security(fastapi.security.HTTPBearer()), +) -> models.Token: + settings = app_settings.Settings() + + token = authorization.credentials + try: + secret_key = settings.project.jwt_secret_key + payload = jose.jwt.decode(token, secret_key, algorithms=[settings.project.jwt_algorithm]) + return models.Token(**payload) + except (jose.JWTError, pydantic.ValidationError) as error: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + ) from error