Spaces:
Running
Running
Upload 3 files
Browse files- core/config.py +25 -0
- core/database.py +25 -0
- core/security.py +73 -0
core/config.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from dotenv import load_dotenv
|
| 4 |
+
from urllib.parse import quote_plus
|
| 5 |
+
from pydantic_settings.base import BaseSettingsModel
|
| 6 |
+
|
| 7 |
+
env_path = Path('.') / '.env'
|
| 8 |
+
load_dotenv(dotenv_path=env_path)
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class Settings(BaseSettingsModel):
|
| 12 |
+
# DATABASE_URL: str
|
| 13 |
+
# DATABASE_NAME: str
|
| 14 |
+
# DATABASE_USER: str
|
| 15 |
+
# DATABASE_PASSWORD: str
|
| 16 |
+
# DATABASE_HOST: str
|
| 17 |
+
# DATABASE_PORT: str
|
| 18 |
+
# DATABASE_URL: str
|
| 19 |
+
# DATABASE_URL = f"postgresql://{DATABASE_USER}:{quote_plus(DATABASE_PASSWORD)}@{DATABASE_HOST}:{DATABASE_PORT}/{DATABASE_NAME}"
|
| 20 |
+
JWT_SECRET_KEY: str = os.getenv("JWT_SECRET")
|
| 21 |
+
JWT_ALGORITHM: str = os.getenv("JWT_ALGORITHM")
|
| 22 |
+
ACCESS_TOKEN_EXPIRE_MINUTES: int = os.getenv("ACCESS_TOKEN")
|
| 23 |
+
|
| 24 |
+
def get_settings():
|
| 25 |
+
return Settings()
|
core/database.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# database.py
|
| 2 |
+
from sqlalchemy import create_engine
|
| 3 |
+
from sqlalchemy.ext.declarative import declarative_base
|
| 4 |
+
from sqlalchemy.orm import sessionmaker
|
| 5 |
+
|
| 6 |
+
SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/dbname"
|
| 7 |
+
|
| 8 |
+
engine = create_engine(
|
| 9 |
+
SQLALCHEMY_DATABASE_URL,
|
| 10 |
+
pool_size=5,
|
| 11 |
+
pool_pre_ping=True,
|
| 12 |
+
pool_recycle=300,
|
| 13 |
+
max_overflow=0
|
| 14 |
+
|
| 15 |
+
)
|
| 16 |
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
| 17 |
+
|
| 18 |
+
Base = declarative_base()
|
| 19 |
+
|
| 20 |
+
def get_db():
|
| 21 |
+
db = SessionLocal()
|
| 22 |
+
try:
|
| 23 |
+
yield db
|
| 24 |
+
finally:
|
| 25 |
+
db.close()
|
core/security.py
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from passlib.context import CryptContext
|
| 2 |
+
from fastapi.security import OAuth2PasswordBearer
|
| 3 |
+
from fastapi import Depends, HTTPException
|
| 4 |
+
from datetime import timedelta, datetime
|
| 5 |
+
from jose import JWTError, jwt
|
| 6 |
+
from core.config import get_settings
|
| 7 |
+
from users.services import get_user_by_email
|
| 8 |
+
from sqlalchemy.orm import Session
|
| 9 |
+
from core.database import get_db
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
settings = get_settings()
|
| 13 |
+
|
| 14 |
+
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
| 15 |
+
oauth2scheme = OAuth2PasswordBearer(tokenUrl="auth/token/")
|
| 16 |
+
|
| 17 |
+
def get_password_hash(password):
|
| 18 |
+
return pwd_context.hash(password)
|
| 19 |
+
|
| 20 |
+
def verify_password(plain_password, hashed_password):
|
| 21 |
+
return pwd_context.verify(plain_password, hashed_password)
|
| 22 |
+
|
| 23 |
+
async def create_access_token(data:dict, expiry:timedelta):
|
| 24 |
+
payload = data.copy()
|
| 25 |
+
expire = datetime.utcnow() + expiry
|
| 26 |
+
payload.update({"exp": expire})
|
| 27 |
+
token = jwt.encode(payload,
|
| 28 |
+
settings.JWT_SECRET_KEY,
|
| 29 |
+
algorithm=settings.JWT_ALGORITHM)
|
| 30 |
+
|
| 31 |
+
return token
|
| 32 |
+
|
| 33 |
+
async def create_refresh_token(data:dict):
|
| 34 |
+
payload = data.copy()
|
| 35 |
+
token = jwt.encode(payload,
|
| 36 |
+
settings.JWT_SECRET_KEY,
|
| 37 |
+
algorithm=settings.JWT_ALGORITHM)
|
| 38 |
+
return token
|
| 39 |
+
|
| 40 |
+
def get_token_payload(token:str):
|
| 41 |
+
try:
|
| 42 |
+
payload = jwt.decode(token,
|
| 43 |
+
settings.JWT_SECRET_KEY,
|
| 44 |
+
algorithms=[settings.JWT_ALGORITHM])
|
| 45 |
+
return payload
|
| 46 |
+
except JWTError:
|
| 47 |
+
return None
|
| 48 |
+
|
| 49 |
+
async def get_current_user(token:str = Depends(oauth2scheme), db:Session = Depends(get_db)):
|
| 50 |
+
try:
|
| 51 |
+
payload = get_token_payload(token)
|
| 52 |
+
email = payload.get("sub")
|
| 53 |
+
if email is None:
|
| 54 |
+
return HTTPException(status_code=401,
|
| 55 |
+
detail="Invalid Token",
|
| 56 |
+
headers={"WWW-Authenticate": "Bearer"})
|
| 57 |
+
except JWTError:
|
| 58 |
+
return HTTPException(status_code=401,
|
| 59 |
+
detail="Invalid Token",
|
| 60 |
+
headers={"WWW-Authenticate": "Bearer"}
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
user = get_user_by_email(email, db=db)
|
| 64 |
+
if user is None:
|
| 65 |
+
return HTTPException(status_code=401,
|
| 66 |
+
detail="Invalid Token",
|
| 67 |
+
headers={"WWW-Authenticate": "Bearer"}
|
| 68 |
+
)
|
| 69 |
+
return user
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
|