JWT refresh tokens remove

This commit is contained in:
2025-09-22 01:58:26 +03:00
parent 909d4d84b6
commit d5003b5dcb
5 changed files with 22 additions and 63 deletions

3
.env
View File

@@ -1,8 +1,7 @@
# JWT configuration # JWT configuration
SECRET_KEY=SUPER_SECRET_KEY SECRET_KEY=SUPER_SECRET_KEY
ALGORITHM=HS256 ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30 ACCESS_TOKEN_EXPIRE_MINUTES=600
REFRESH_TOKEN_EXPIRE_MINUTES=6000
# CORS-middleware # CORS-middleware
# ALLOW_ORIGINS=*, # "*" — разрешить всем; можно указать список конкретных доменов # ALLOW_ORIGINS=*, # "*" — разрешить всем; можно указать список конкретных доменов
# ALLOW_CREDENTIALS=True, # ALLOW_CREDENTIALS=True,

View File

@@ -11,7 +11,6 @@ load_dotenv()
SECRET_KEY = os.getenv('SECRET_KEY') SECRET_KEY = os.getenv('SECRET_KEY')
ALGORITHM = os.getenv('ALGORITHM') ALGORITHM = os.getenv('ALGORITHM')
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv('ACCESS_TOKEN_EXPIRE_MINUTES')) ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv('ACCESS_TOKEN_EXPIRE_MINUTES'))
REFRESH_TOKEN_EXPIRE_MINUTES = int(os.getenv('REFRESH_TOKEN_EXPIRE_MINUTES'))
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login") #Создание jwt oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login") #Создание jwt
class Token(): class Token():
@@ -26,12 +25,6 @@ class AccessToken(Token):
@staticmethod @staticmethod
async def create(data:dict, expires_delta: timedelta | None = None): async def create(data:dict, expires_delta: timedelta | None = None):
return await Token.create_token(data, expires_delta) return await Token.create_token(data, expires_delta)
class RefreshToken(Token):
@staticmethod
async def create(data:dict, expires_delta: timedelta | None = None):
token_str = await Token.create_token(data, expires_delta)
await db.refresh_token(encoded_jwt = token_str,email=data["sub"])
return token_str
async def current_user(token: str = Depends(oauth2_scheme)): #Проверка jwt async def current_user(token: str = Depends(oauth2_scheme)): #Проверка jwt
try: try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])

View File

@@ -1,6 +1,7 @@
from fastapi import FastAPI, HTTPException, status, Depends from fastapi import FastAPI, HTTPException, status, Depends
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from fastapi.security import OAuth2PasswordRequestForm
from . import pydentic, JWT from . import pydentic, JWT
from datetime import datetime, timedelta from datetime import datetime, timedelta
from pydantic import EmailStr from pydantic import EmailStr
@@ -28,40 +29,35 @@ api.add_middleware(
async def protected(current_user: str = Depends(JWT.current_user)): async def protected(current_user: str = Depends(JWT.current_user)):
return {"msg": f"Hello, {current_user}"} return {"msg": f"Hello, {current_user}"}
@api.get("/", response_model=pydentic.IdofPersons) @api.get("/", response_model=pydentic.CreateUser)
async def get_all_rows(current_user: str = Depends(JWT.current_user)): async def get_all_rows(current_user: str = Depends(JWT.current_user)):
for row in await db.get_all_rows(): for row in await db.get_all_rows():
if row: if row:
return row return row
else: else:
raise HTTPException(status_code=404, detail="The user isn't found") raise HTTPException(status_code=404, detail="The user isn't found")
@api.get("/get_user_by_id/{id}", response_model=pydentic.IdofPersons) @api.get("/get_user_by_email/{email}", response_model=pydentic.CreateUser)
async def get_user(id: int, current_user: str = Depends(JWT.current_user)): async def GetUserbyEmail(email:str, current_user: str = Depends(JWT.current_user)):
user = await db.GetUser(id) user = await db.GetUserbyEmail(email)
if user: if user:
return user return user
else: else:
raise HTTPException(status_code=404, detail="The user isn't found") raise HTTPException(status_code=404, detail="The user isn't found")
@api.post("/user_create", response_model=pydentic.IdofPersons) @api.post("/user_create", response_model=pydentic.CreateUser)
async def create_user(row:pydentic.CreateUser): async def create_user(row:pydentic.CreateUser):
rows = await db.get_all_rows() new_row = pydentic.CreateUser(email=row.email, description=row.description, activated = row.activated, password = row.password)
if rows:
new_user_id = max(item.id for item in rows) + 1
else:
new_user_id = 1
new_row = pydentic.IdofPersons(id = new_user_id, email=row.email, description=row.description, activated = row.activated, password = row.password)
await db.CreateUser(new_row) await db.CreateUser(new_row)
return new_row return new_row
@api.delete("/user_delete/{id}", response_model=pydentic.IdofPersons) @api.delete("/user_delete/{email}", response_model=pydentic.CreateUser)
async def delete_user(id: int,current_user: str = Depends(JWT.current_user)): async def delete_user(email:str,current_user: str = Depends(JWT.current_user)):
user = await db.GetUser(id) user = await db.GetUserbyEmail(email)
if not user: if not user:
raise HTTPException(status_code=404, detail="The user isn't found") raise HTTPException(status_code=404, detail="The user isn't found")
await db.DeleteUser(id) await db.DeleteUser(email)
return user return user
@api.put("/user_update/{id}", response_model=pydentic.IdofPersons) @api.put("/user_update/{email}", response_model=pydentic.CreateUser)
async def update_user(id: int, updated_row: pydentic.UserUpdate, current_user: str = Depends(JWT.current_user)): async def update_user(email:str, updated_row: pydentic.UserUpdate, current_user: str = Depends(JWT.current_user)):
user = await db.GetUser(id) user = await db.GetUserbyEmail(email)
if not user: if not user:
raise HTTPException(status_code=404, detail="The user isn't found") raise HTTPException(status_code=404, detail="The user isn't found")
changed = False changed = False
@@ -83,33 +79,14 @@ async def update_user(id: int, updated_row: pydentic.UserUpdate, current_user: s
pass pass
return user return user
@api.post("/login") @api.post("/login")
async def login_user(row: pydentic.UserLogin): async def login_user(form_data: OAuth2PasswordRequestForm = Depends()):
user = await db.LoginUser(row) creds = pydentic.UserLogin(email=form_data.username, password=form_data.password)
user = await db.LoginUser(creds)
if not user: if not user:
raise HTTPException(status_code=401, detail="The user isn't found") raise HTTPException(status_code=401, detail="The user isn't found")
access_token = await JWT.AccessToken.create( access_token = await JWT.AccessToken.create(
{"sub": user.email}, {"sub": user.email},
timedelta(minutes=JWT.ACCESS_TOKEN_EXPIRE_MINUTES) timedelta(minutes=JWT.ACCESS_TOKEN_EXPIRE_MINUTES)
) )
refresh_token = await JWT.RefreshToken.create( return {"access_token": access_token, "token_type": "bearer"}
{"sub": user.email},
timedelta(minutes=JWT.REFRESH_TOKEN_EXPIRE_MINUTES)
)
response = JSONResponse(content={
"access_token": access_token,
"token_type": "bearer"
})
response.set_cookie(
key="refresh_token",
value=refresh_token,
httponly=True,
secure=False, # только https
samesite="strict" # чтобы не утекал на другие сайты
)
return response
@api.post("/logout")
async def logout_user(row: pydentic.UserLogout):
user = await db.GetUserbyEmail(row)
if not user:
raise HTTPException(status_code=401, detail="The user isn't found")
await db.refresh_token(encoded_jwt = Null,email=user.email)

View File

@@ -23,8 +23,6 @@ class UsersInfo(BaseModel):
@validator('password') @validator('password')
def password_validator(cls, password): def password_validator(cls, password):
return check_password_complexity(cls, password) return check_password_complexity(cls, password)
class IdofPersons(UsersInfo):
id:int = Field(..., description="Unique identifier of the user")
class CreateUser(UsersInfo): class CreateUser(UsersInfo):
pass pass
class UserUpdate(BaseModel): class UserUpdate(BaseModel):

View File

@@ -33,7 +33,6 @@ class User(Base):
description = Column(String, nullable=False) description = Column(String, nullable=False)
activated = Column(Boolean, default=False) activated = Column(Boolean, default=False)
password = Column(String, nullable=False) password = Column(String, nullable=False)
refresh_token = Column(String, nullable=True)
async def init_db(): async def init_db():
async with async_engine.begin() as conn: async with async_engine.begin() as conn:
@@ -64,9 +63,9 @@ async def UpdateUser(user_info):
user.activated = user_info.activated user.activated = user_info.activated
user.password = hash_password(user_info.password) user.password = hash_password(user_info.password)
await session.commit() await session.commit()
async def DeleteUser(id): async def DeleteUser(email):
async with AsyncSessionLocal() as session: async with AsyncSessionLocal() as session:
result = await session.execute(select(User).where(User.id==id)) result = await session.execute(select(User).where(User.email==email))
user = result.scalar_one_or_none() user = result.scalar_one_or_none()
if user: if user:
await session.delete(user) await session.delete(user)
@@ -78,12 +77,5 @@ async def LoginUser(user_info):
if user and verify_password(user_info.password, user.password): if user and verify_password(user_info.password, user.password):
return user return user
return None return None
async def refresh_token(encoded_jwt, email):
async with AsyncSessionLocal() as session:
result = await session.execute(select(User).where(User.email==email))
user = result.scalar_one_or_none()
if user:
user.refresh_token = encoded_jwt
await session.commit()
async def main(): async def main():
await init_db() await init_db()