Git Commit: create access token route
Authentication means identifying a user. They should be what they are claiming they are. In simple words, it refers to the login functionality in our app. In the previous post, we implemented a logic to create JWT tokens. Our authentication logic will be relying on JWT tokens. Basically, our web app users will send their email and password, we will verify the credentials and send them a JWT token. Let's add these functions in a file apis > v1 > route_login.py
from fastapi.security import OAuth2PasswordRequestForm
from fastapi import Depends,APIRouter
from sqlalchemy.orm import Session
from fastapi import status,HTTPException
from db.session import get_db
from core.hashing import Hasher
from schemas.token import Token
from db.repository.login import get_user
from core.security import create_access_token
router = APIRouter()
def authenticate_user(email: str, password: str,db: Session):
user = get_user(email=email,db=db)
print(user)
if not user:
return False
if not Hasher.verify_password(password, user.password):
return False
return user
@router.post("/token", response_model=Token)
def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(),db: Session= Depends(get_db)):
user = authenticate_user(form_data.username, form_data.password,db)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
)
access_token = create_access_token(
data={"sub": user.email}
)
return {"access_token": access_token, "token_type": "bearer"}
Note: we will be working with email only, but our Outh2PasswordRequestForm is bound to have a field named 'username'. No issues, we will let our users enter their email and query the db using email only! The 'username' field does not restrict us to enter a username😁! We need a schema to verify that we are returning an access_token and token_type as defined in our response_model. Let's put this code in schemas > token.py
from pydantic import BaseModel
class Token(BaseModel):
access_token: str
token_type: str
We also need a function that will return a user given the email. Let's create this function in db > repository > login.py. Again, we are doing this because we want to keep the database orm logic separate from our business logic. This is an example of separation of concerns.
from sqlalchemy.orm import Session
from db.models.user import User
def get_user(email:str,db: Session):
user = db.query(User).filter(User.email == email).first()
return user
Almost there, now we need to tell our FastAPI app that there is this functionality. For that, we need to put these 2 lines in apis > base.py
from apis.v1 import route_blog
from apis.v1 import route_user
from apis.v1 import route_login
from fastapi import APIRouter
api_router = APIRouter()
api_router.include_router(route_user.router, prefix="", tags=["users"])
api_router.include_router(route_blog.router, prefix="", tags=["blogs"])
api_router.include_router(route_login.router, prefix="", tags=["login"])
One last thing, since we are working with form data and not simple JSON, we need a python-multipart library to handle the retrieval of form data. So, let's add this in requirement.txt and do a pip install -r requirements.txt
fastapi==0.95.1
python-multipart==0.0.6
Time to test our implementation: I am using Postman this time, you may also try it with automatic docs. The results will be the same.
Brige the gap between Tutorial hell and Industry. We want to bring in the culture of Clean Code, Test Driven Development.
We know, we might make it hard for you but definitely worth the efforts.
© Copyright 2022-23 Team FastAPITutorial