structure auth
This commit is contained in:
BIN
server/__pycache__/config.cpython-311.pyc
Normal file
BIN
server/__pycache__/config.cpython-311.pyc
Normal file
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
fastapi==0.128.6
|
||||
sqlmodel==0.0.32
|
||||
python-dotenv==1.2.1
|
||||
openai==2.21.0
|
||||
spacy==3.8.11
|
||||
PyJWT>=2.11.0
|
||||
|
||||
@@ -3,4 +3,3 @@ LANGUAGE_MODEL_API="http://localhost:8080/v1"
|
||||
LANGUAGE_MODEL_NAME="SmolLM3-Q4_K_M.gguf"
|
||||
ORIGIN="http://localhost:5173"
|
||||
SECRET_KEY="xxxx" #generate secure random secret key: openssl rand -hex 32
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES=10080
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,9 +2,9 @@ from fastapi import APIRouter
|
||||
|
||||
from .knowledges import router as knowledge_router
|
||||
from .metrics import router as metric_router
|
||||
from .users import router as user_router
|
||||
from .auth import router as auth_router
|
||||
|
||||
router = APIRouter(prefix="/v1")
|
||||
router.include_router(knowledge_router)
|
||||
router.include_router(metric_router)
|
||||
router.include_router(user_router)
|
||||
router.include_router(auth_router)
|
||||
Binary file not shown.
BIN
server/src/app/api/v1/__pycache__/auth.cpython-311.pyc
Normal file
BIN
server/src/app/api/v1/__pycache__/auth.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
@@ -2,11 +2,13 @@ from typing import Annotated
|
||||
|
||||
from fastapi import Depends, APIRouter, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer
|
||||
from datetime import timedelta
|
||||
|
||||
from src.app.models.user import User
|
||||
from src.app.data.user import create_user
|
||||
from src.app.services.auth import get_current_user, authenticate_user, create_access_token, hash_password, Token
|
||||
|
||||
from src.app.auth.dependancies import get_current_user, authenticate_user
|
||||
from src.app.auth.security import hash_password, create_access_token
|
||||
from src.app.auth.schemas import Token
|
||||
|
||||
router = APIRouter(tags=["users"])
|
||||
|
||||
BIN
server/src/app/auth/__pycache__/auth.cpython-311.pyc
Normal file
BIN
server/src/app/auth/__pycache__/auth.cpython-311.pyc
Normal file
Binary file not shown.
BIN
server/src/app/auth/__pycache__/dependancies.cpython-311.pyc
Normal file
BIN
server/src/app/auth/__pycache__/dependancies.cpython-311.pyc
Normal file
Binary file not shown.
BIN
server/src/app/auth/__pycache__/schemas.cpython-311.pyc
Normal file
BIN
server/src/app/auth/__pycache__/schemas.cpython-311.pyc
Normal file
Binary file not shown.
BIN
server/src/app/auth/__pycache__/security.cpython-311.pyc
Normal file
BIN
server/src/app/auth/__pycache__/security.cpython-311.pyc
Normal file
Binary file not shown.
@@ -1,35 +1,21 @@
|
||||
from src.app.config import settings
|
||||
from datetime import timedelta, datetime, timezone
|
||||
from typing import Annotated
|
||||
from pydantic import BaseModel
|
||||
|
||||
from typing import Annotated
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from argon2 import PasswordHasher
|
||||
from argon2 import PasswordHasher
|
||||
import jwt
|
||||
from jwt.exceptions import InvalidTokenError
|
||||
from argon2 import PasswordHasher
|
||||
from argon2.exceptions import (
|
||||
VerifyMismatchError,
|
||||
VerificationError,
|
||||
InvalidHashError,
|
||||
)
|
||||
|
||||
from src.app.models.user import User
|
||||
from src.app.data.user import get_user
|
||||
from .schemas import TokenData
|
||||
from .security import verify_password
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/token")
|
||||
password_hasher = PasswordHasher()
|
||||
|
||||
algorithm = "HS256"
|
||||
access_token_expire_minutes = 10080
|
||||
|
||||
class Token(BaseModel):
|
||||
access_token: str
|
||||
token_type: str
|
||||
|
||||
class TokenData(BaseModel):
|
||||
username: str | None = None
|
||||
|
||||
def authenticate_user(username: str, password: str):
|
||||
user: User = get_user(username)
|
||||
if not user:
|
||||
@@ -40,23 +26,6 @@ def authenticate_user(username: str, password: str):
|
||||
return False
|
||||
return user
|
||||
|
||||
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||
isValidated: bool = False
|
||||
try:
|
||||
return password_hasher.verify(hashed_password, plain_password)
|
||||
except (VerifyMismatchError, VerificationError, InvalidHashError):
|
||||
return False
|
||||
|
||||
def create_access_token(data: dict):
|
||||
expire = datetime.now(timezone.utc) + timedelta(minutes=access_token_expire_minutes)
|
||||
to_encode = data.copy()
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=algorithm)
|
||||
return encoded_jwt
|
||||
|
||||
async def hash_password(password: str) -> str:
|
||||
return password_hasher.hash(password)
|
||||
|
||||
async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]) -> User:
|
||||
credentials_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
@@ -64,7 +33,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]) -> Use
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
try:
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithm=algorithm)
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
||||
username = payload.get("sub")
|
||||
if username is None:
|
||||
raise credentials_exception
|
||||
8
server/src/app/auth/schemas.py
Normal file
8
server/src/app/auth/schemas.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
class Token(BaseModel):
|
||||
access_token: str
|
||||
token_type: str
|
||||
|
||||
class TokenData(BaseModel):
|
||||
username: str | None = None
|
||||
33
server/src/app/auth/security.py
Normal file
33
server/src/app/auth/security.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from src.app.config import settings
|
||||
from datetime import timedelta, datetime, timezone
|
||||
from argon2 import PasswordHasher
|
||||
from argon2.exceptions import (
|
||||
VerifyMismatchError,
|
||||
VerificationError,
|
||||
InvalidHashError,
|
||||
)
|
||||
import jwt
|
||||
from jwt.exceptions import InvalidTokenError
|
||||
|
||||
|
||||
password_hasher = PasswordHasher()
|
||||
|
||||
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||
try:
|
||||
return password_hasher.verify(hashed_password, plain_password)
|
||||
except (VerifyMismatchError, VerificationError, InvalidHashError):
|
||||
return False
|
||||
|
||||
def hash_password(password: str) -> str:
|
||||
return password_hasher.hash(password)
|
||||
|
||||
def create_access_token(data: dict):
|
||||
expire = datetime.now(timezone.utc) + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
to_encode = data.copy()
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
||||
#def create_refresh_token(data: dict) -> str:
|
||||
|
||||
#def verify_token(token: str, token_type: str = "access") -> Optional[dict]:
|
||||
@@ -1,17 +1,19 @@
|
||||
from pydantic_settings import BaseSettings
|
||||
from pydantic import Field
|
||||
|
||||
class Settings(BaseSettings):
|
||||
# Database
|
||||
DATABASE_URI: str
|
||||
DATABASE_URI: str = Field("sqlite:///database.db", env='DATABASE_URI')
|
||||
|
||||
# Language model
|
||||
LANGUAGE_MODEL_API: str = "http://localhost:8080/v1"
|
||||
LANGUAGE_MODEL_NAME: str = "SmolLM3-Q4_K_M.gguf"
|
||||
LANGUAGE_MODEL_API: str = Field("http://localhost:8080/v1", env='LANGUAGE_MODEL_API')
|
||||
LANGUAGE_MODEL_NAME: str = Field("SmolLM3-Q4_K_M.gguf", env='LANGUAGE_MODEL_NAME')
|
||||
|
||||
# Security
|
||||
ORIGIN: str
|
||||
SECRET_KEY : str
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: int
|
||||
ORIGIN: str = Field('http://localhost:5173', env='ORIGIN')
|
||||
SECRET_KEY : str = Field('random_string', env='SECRET_KEY')
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
|
||||
ALGORITHM: str = "HS256"
|
||||
|
||||
class Config:
|
||||
env_file = ".env"
|
||||
|
||||
0
server/src/app/data/__init__.py
Normal file
0
server/src/app/data/__init__.py
Normal file
BIN
server/src/app/data/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
server/src/app/data/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
@@ -6,7 +6,8 @@ from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
from src.app.database import create_db_and_tables
|
||||
|
||||
#TODO : best practice to manage models import
|
||||
# Import models in app
|
||||
# TODO : best practice to manage models import
|
||||
from src.app.models.question import Question
|
||||
from src.app.models.knowledge import Knowledge
|
||||
from src.app.models.metric import Metric
|
||||
@@ -14,7 +15,7 @@ from src.app.models.user import User
|
||||
|
||||
from .api import router
|
||||
|
||||
#Test
|
||||
#Fake data
|
||||
from src.app.faker_seed import faker
|
||||
|
||||
#TODO : alternative @app.on_event("startup") ?
|
||||
|
||||
0
server/src/app/models/__init__.py
Normal file
0
server/src/app/models/__init__.py
Normal file
BIN
server/src/app/models/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
server/src/app/models/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
@@ -4,3 +4,4 @@ class User(SQLModel, table=True):
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
username: str
|
||||
hashed_password: str
|
||||
#is_active: bool
|
||||
Binary file not shown.
Reference in New Issue
Block a user