Skip to content

Commit

Permalink
✅Backend API Final
Browse files Browse the repository at this point in the history
  • Loading branch information
mihirh19 committed Mar 31, 2023
1 parent 94f73fd commit 32fdf7d
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 17 deletions.
7 changes: 7 additions & 0 deletions .idea/todo.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion backend/app/api/api_v1/router.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from fastapi import APIRouter
from .handlers import user
from .handlers import user, todo
from ..auth.jwt import auth_router

router = APIRouter()

router.include_router(user.user_router, prefix='/users', tags=['users'])
router.include_router(auth_router, prefix='/auth', tags=['auth'])
router.include_router(todo.todo_router, prefix='/todo', tags=['todo'])

47 changes: 43 additions & 4 deletions backend/app/api/auth/jwt.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,59 @@
from fastapi import APIRouter, Depends, HTTPException, status
from datetime import datetime

from fastapi import APIRouter, Depends, HTTPException, status, Body
from fastapi.security import OAuth2PasswordRequestForm
from typing import Any

from jose import jwt
from pydantic import ValidationError

from ..deps.user_deps import get_current_user
from ...core.config import settings
from ...models.user_model import User
from ...services.user_services import UserService
from ...core.security import create_refresh_token, create_access_token
from ...schemas.auth_schema import TokenSchema, TokenPayload
from ...schemas.user_schema import UserOut

auth_router = APIRouter()


@auth_router.post('/login')
@auth_router.post('/login', summary="Create access and refresh token", response_model=TokenSchema)
async def login(form_data: OAuth2PasswordRequestForm = Depends()) -> Any:
user = await UserService.authenticate(email=form_data.username, password=form_data.password)
if not user:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="incorrect email or password")

# create a access and refresh token
return {
"access_token" : create_access_token(user.user_id),
"refresh_token" : create_refresh_token(user.user_id)
"access_token": create_access_token(user.user_id),
"refresh_token": create_refresh_token(user.user_id)
}


@auth_router.post('/test-token', summary="test if the access token is vaild", response_model=UserOut)
async def tset_token(user: User = Depends(get_current_user)):
return user


@auth_router.post('/refresh', summary="refresh token", response_model=TokenSchema)
async def refresh_token(refresh_token:str = Body(...)):
try:
payload = jwt.decode(refresh_token, settings.JWT_REFRESH_SECRET_KEY, algorithms=[settings.ALGORITHM])
token_data = TokenPayload(**payload)
if datetime.fromtimestamp(token_data.exp) < datetime.now():
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired",
headers={"WWW-Authenticate": "Bearer"})
except(jwt.JWTError, ValidationError):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"})

user = await UserService.get_user_by_id(token_data.sub)

if not user:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Could not find user")

return {
"access_token":create_access_token(user.user_id),
"refresh_token": create_refresh_token(user.user_id)
}
28 changes: 23 additions & 5 deletions backend/app/api/deps/user_deps.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
from fastapi.security import OAuth2PasswordBearer
from fastapi import Depends
from fastapi import Depends, HTTPException, status
from ...core.config import settings
from ...models.user_model import User
from ...services.user_services import UserService
from jose import jwt
from datetime import datetime
from pydantic import ValidationError
from ...schemas.auth_schema import TokenPayload

reuseble_oauth = OAuth2PasswordBearer(
tokenUrl=f"{settings.API_V1_STR1}/auth/login",
tokenUrl=f"{settings.API_V1_STR}/auth/login",
scheme_name="JWT"
)

async def get_current_user(token:str = Depends(reuseble_oauth))->User:

async def get_current_user(token: str = Depends(reuseble_oauth)) -> User:
try:
payload = jwt.decode(token, settings.JWT_SECRET_KEY, algorithms=[settings.ALGORITHM])
finally:
pass
token_data = TokenPayload(**payload)
if datetime.fromtimestamp(token_data.exp) < datetime.now():
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired",
headers={"WWW-Authenticate": "Bearer"})
except(jwt.JWTError, ValidationError):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"})

user = await UserService.get_user_by_id(token_data.sub)

if not user:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Could not find user")

return user
5 changes: 3 additions & 2 deletions backend/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from motor.motor_asyncio import AsyncIOMotorClient
from .models.user_model import User
from .api.api_v1.router import router

from .models.todo_model import Todo
app = FastAPI(
title=settings.PROJECT_NAME,
openapi_url=f"{settings.API_V1_STR}/openapi.json"
Expand All @@ -20,7 +20,8 @@ async def app_init():
await init_beanie(
database=db_client,
document_models=[
User
User,
Todo
]
)

Expand Down
9 changes: 8 additions & 1 deletion backend/app/schemas/auth_schema.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
from uuid import UUID

from pydantic import BaseModel

class TokenSchema(BaseModel):
acces_token : str
access_token : str
refresh_token : str


class TokenPayload(BaseModel):
sub : UUID = None
exp : int
13 changes: 9 additions & 4 deletions backend/app/services/user_services.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Optional
from uuid import UUID

from ..schemas.user_schema import UserAuth
from ..models.user_model import User
Expand All @@ -17,15 +18,19 @@ async def create_user(user: UserAuth):
return user_in

@staticmethod
async def authenticate(email:str, password:str)->Optional[User]:
async def authenticate(email: str, password: str) -> Optional[User]:
user = await UserService.get_user_by_email(email)
if not user:
return None
if not verify_password(password= password, hashed_password=user.hashed_password):
if not verify_password(password=password, hashed_password=user.hashed_password):
return None
return user

@staticmethod
async def get_user_by_email(email:str)->Optional[User]:
async def get_user_by_email(email: str) -> Optional[User]:
user = await User.find_one(User.email == email)
return user
return user

async def get_user_by_id(id: UUID) -> Optional[User]:
user = await User.find_one(User.user_id == id)
return user

0 comments on commit 32fdf7d

Please sign in to comment.