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 |
+
|