[FastAPI] FastAPI 를 활용한 토큰 기반 인증

도톨이·2024년 4월 12일

FastAPI

목록 보기
17/17
post-thumbnail

오늘은 지난 시간에 이어 TodoProject 를 진행할 것이다.
지난 시간에는 유저 생성 시 비밀번호 해싱, db 에 add 하는 방법을 배웠다.

이번 시간에는 토큰 기반 인증을 배워볼 것이다.

우선, 가상환경 내부에서 python-multipart 를 설치한다.

pip install python-multipart

python-multipart 는 python 에서 multipart/form-data 파싱을 처리하기 위한 라이브러리이다.

이 라이브러리는 주로 파일 업로드 및 다중 파트 폼 데이터를 수신할 때 사용된다.

그리고 OAuth2PasswordRequestForm 을 사용할 것이다. 이는 fastapi에서 제공하는 클래스로 OAuth2의 패스워드 그랜트 유형에 따라 사용자 인증을 처리하는 데 사용된다.

이 폼을 사용하면 사용자로부터 username 과 password 를 안전하게 받아서 OAuth2 토큰을 발급할 수 있다.

OAuth2PasswordRequestForm 는 1. 사용자의 로그인 요청을 처리하고, 검증하여 유효한 경우 2. 액세스 토큰을 발급한다.

토큰이란?

토큰은 쉽게 비유하자면, 놀이공원에 가면 입장권이 필요하듯이 컴퓨터나 핸드폰에서 특별한 곳에 들어가기 위한 '입장권'같은 것이다.
만약 게임을 할 때 특별한 비밀번호를 받게되는 경우가 있다. 우리는 이런 걸 토큰이라하고 이 토큰이 있어야 게임을 할 수가 있다.

다시 돌아와서, 토큰은 사용자나 시스템이 서로를 식별하고 정보에 접근하는 것을 안전하게 하기 위해 사용된다.

토큰을 사용하면 다음의 이점이 있다.

  • 보안성 : 권한을 제한적으로 부여하여 보안성 높음
  • 상태 비저장성 : 서버는 세션 정보 유지할 필요없이 사용자 요청 인증할 수 있어서 서버의 부하 줄임

코드

from fastapi import APIRouter, Depends
from pydantic import BaseModel
from sqlalchemy.orm import Session
from starlette import status
from typing import Annotated

from database import SessionLocal
from models import Users
from passlib.context import CryptContext
from fastapi.security import OAuth2PasswordRequestForm

router = APIRouter()

bcrypt_context = CryptContext(schemes=['bcrypt'], deprecated='auto')

#pydantic
class CreateUserRequest(BaseModel):
    username: str
    email: str
    first_name: str
    last_name : str
    password: str
    role: str

def get_db():
    db = SessionLocal()
    try:
        yield  db
    finally:
        db.close()

db_dependency = Annotated[Session, Depends(get_db)]



def authenticaate_user(username: str, password: str, db):
    user = db.query(Users).filter(Users.username == username).first()
    if not user:
        return False
    if not bcrypt_context.verify(password, user.hashed_password):
        return False
    return True

@router.post("/auth", status_code =status.HTTP_201_CREATED)
async def create_user(db: db_dependency,
        create_user_request: CreateUserRequest):
    create_user_model = Users(
        email=create_user_request.email,
        usedbrname=create_user_request.username,
        first_name=create_user_request.first_name,
        last_name=create_user_request.last_name,
        role=create_user_request.role,
        # 비밀 번호는 해싱되어야함.
        hashed_password=bcrypt_context.hash(create_user_request.password),
        is_active=True
    )
    db.add(create_user_model)
    db.commit()

@router.post("/token")
async def login_for_access_token(form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
                                 db: db_dependency):
    user = authenticaate_user(form_data.username, form_data.password, db)
    if not user:
        return 'Failed Authentication'
    return 'Successful Authentication'


# 인증. 라우터 패키지 안에 존재
@router.get("/auth")
async def get_user():
    return {'user': 'authenticated'}


profile
Kotlin, Flutter, AI | Computer Science

0개의 댓글