Remove token revocation logic and unused dependencies
Eliminated the `RevokedToken` model and associated logic for managing token revocation. Removed unused files, related tests, and outdated dependencies in authentication modules. Simplified token decoding, user validation, and dependency injection by streamlining the flow and enhancing maintainability.
This commit is contained in:
@@ -1,134 +1,3 @@
|
||||
from typing import Any
|
||||
|
||||
from app.auth.utils import revoke_token, is_token_revoked
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.auth.security import authenticate_user, create_access_token, create_refresh_token, decode_token
|
||||
from app.core.database import get_db
|
||||
from app.models.user import User
|
||||
from app.schemas.token import TokenResponse, TokenPayload, RefreshToken
|
||||
from app.schemas.user import UserResponse
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
oauth2_scheme = OAuth2PasswordRequestForm
|
||||
|
||||
|
||||
# Existing: User Login Endpoint
|
||||
@router.post(
|
||||
"/auth/login",
|
||||
response_model=TokenResponse,
|
||||
summary="Authenticate user and provide tokens"
|
||||
)
|
||||
async def login(
|
||||
form_data: OAuth2PasswordRequestForm = Depends(),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
) -> Any:
|
||||
"""
|
||||
Authenticate a user with their credentials and return an access and refresh token.
|
||||
"""
|
||||
user = await authenticate_user(email=form_data.username, password=form_data.password, db=db)
|
||||
if not user:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials.")
|
||||
|
||||
# Generate access and refresh tokens
|
||||
access_token = create_access_token({"sub": str(user.id), "type": "access"})
|
||||
refresh_token = create_refresh_token({"sub": str(user.id), "type": "refresh"})
|
||||
|
||||
return TokenResponse(
|
||||
access_token=access_token,
|
||||
refresh_token=refresh_token,
|
||||
token_type="bearer",
|
||||
expires_in=1800, # Example: 30 minutes for access token
|
||||
user_id=str(user.id),
|
||||
)
|
||||
|
||||
|
||||
# New: Logout Endpoint (Revoke Token)
|
||||
@router.post(
|
||||
"/auth/logout",
|
||||
summary="Revoke the current token",
|
||||
response_model=dict,
|
||||
status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def logout(
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(
|
||||
lambda token=Depends(oauth2_scheme), db=Depends(get_db): decode_token(token, db=db))
|
||||
):
|
||||
"""
|
||||
Logout the user by revoking the current token.
|
||||
"""
|
||||
# Decode the token and revoke it
|
||||
payload: TokenPayload = await decode_token(token, db=db)
|
||||
await revoke_token(payload.jti, payload.type, payload.sub, db)
|
||||
|
||||
return {"message": "Successfully logged out."}
|
||||
|
||||
|
||||
# New: Bulk Logout (Revoke All of a User's Tokens)
|
||||
@router.post(
|
||||
"/auth/logout-all",
|
||||
summary="Revoke all active tokens for the user",
|
||||
response_model=dict,
|
||||
status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def logout_all(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(
|
||||
lambda token=Depends(oauth2_scheme), db=Depends(get_db): decode_token(token, db=db))
|
||||
):
|
||||
"""
|
||||
Revoke all tokens for the current user, effectively logging them out across all devices.
|
||||
"""
|
||||
await db.execute("DELETE FROM revoked_tokens WHERE user_id = :user_id", {"user_id": str(current_user.id)})
|
||||
await db.commit()
|
||||
|
||||
return {"message": "Logged out from all devices."}
|
||||
|
||||
|
||||
# Updated: Refresh Token Endpoint
|
||||
@router.post(
|
||||
"/auth/refresh-token",
|
||||
response_model=TokenResponse,
|
||||
summary="Generate a new access token using a refresh token"
|
||||
)
|
||||
async def refresh_token(
|
||||
refresh_token: RefreshToken,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
) -> TokenResponse:
|
||||
"""
|
||||
Refresh the user's access token using their refresh token while ensuring it has not been revoked.
|
||||
"""
|
||||
payload: TokenPayload = await decode_token(refresh_token.refresh_token, required_type="refresh", db=db)
|
||||
|
||||
if await is_token_revoked(payload.jti, db):
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=f"Token has been revoked.")
|
||||
|
||||
# Generate a new access token with the user's info
|
||||
new_access_token = create_access_token({"sub": payload.sub, "type": "access"})
|
||||
return TokenResponse(
|
||||
access_token=new_access_token,
|
||||
refresh_token=refresh_token.refresh_token, # Reuse existing refresh token
|
||||
expires_in=1800, # Example: 30 minutes expiry for access token
|
||||
token_type="bearer",
|
||||
user_id=payload.sub,
|
||||
)
|
||||
|
||||
|
||||
# Existing: Get Current User Endpoint
|
||||
@router.get(
|
||||
"/auth/me",
|
||||
response_model=UserResponse,
|
||||
summary="Get user details from the token"
|
||||
)
|
||||
async def read_users_me(
|
||||
current_user: User = Depends(
|
||||
lambda token=Depends(oauth2_scheme), db=Depends(get_db): decode_token(token, db=db))
|
||||
) -> UserResponse:
|
||||
"""
|
||||
Retrieves the details of the currently authenticated user.
|
||||
"""
|
||||
return current_user
|
||||
|
||||
Reference in New Issue
Block a user