이전 포스팅에서 Fast API로 기본적인 게시판에 대한 CRUD API를 구현하였고, 이번 포스팅에서는 JWT를 활용한 로그인, 로그아웃 API를 구현하려고 한다.
➡️이전글
2025.05.27 - [WEB 개발] - [FastAPI] CRUD API 구현 (SQLAlchemy, RESTful API)
[FastAPI] CRUD API 구현 (SQLAlchemy, RESTful API)
FastAPI + RESTful API 구현이전 회사에서 FastAPI로 개발을 하였으나, RESTful 하지 않게 설계도 하였고 정리도 해볼겸 간단한 CRUD API를 RESTful 하게 구현 해보려 한다. ▶ RESTful API 에 관련된 내용은 이전
mayhun.tistory.com
2025.06.01 - [WEB 개발] - [JWT] JWT 토큰 이란?
[JWT] JWT 토큰 이란?
1. 인증(Authentication)이란?인증(Authentication)은 시스템이나 서비스가 사용자가 누구인지 확인하는 과정사용자가 주장하는 신원이 실제로 그 사람인지 확인2. JWT 토큰이란?JWT (JSON Web Token) 는 이름 그
mayhun.tistory.com
환경변수 추가
JWT를 사용하기 위해 환경변수를 추가한다
- SECRET_KEY: JWT 토큰을 생성하고 검증할 때 사용하는 서명 키로, 외부에 노출되면 보안 위협이 발생할수 있음
- ALGORITHM: JWT 서명에 사용할 암호화 알고리즘
- ACCESS_TOKEN_EXPIRE_MINUTES: 토큰의 유효기간
# .env
DB_USER='root'
DB_PASSWD='1234'
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=fastapi_crud
# 추가내용
SECRET_KEY=may
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
JWT utils 작성
- app/utils/jwt.py
- create_access_token 함수는 로그인 성공시 사용자 정보를 포함한 JWT를 생성
import os
from datetime import datetime, timedelta
from jose import jwt
SECRET_KEY = os.getenv("SECRET_KEY")
if not SECRET_KEY:
raise ValueError("SECRET_KEY is not set in environment variables.")
ALGORITHM = os.getenv("ALGORITHM", "HS256")
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", 30))
def create_access_token(data: dict, expires_delta: timedelta = None) -> str:
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
토큰 반환 스키마 작성
- app/schema.py
class TokenResponse(BaseModel):
access_token: str
token_type: str = "bearer"
로그인 API 엔드포인트 구현
- app/touers/auth.py
from fastapi import APIRouter, Depends, HTTPException, status, Response
from sqlalchemy.orm import Session
from app.database import get_db
from app import crud
from app.utils.security import verify_password
from app.utils.jwt import create_access_token
from app.schema import LoginRequest, TokenResponse
router = APIRouter(prefix="/auth", tags=["auth"])
@router.post("/login", response_model=TokenResponse, summary="로그인 및 JWT 토큰 발급")
def login(request: LoginRequest, response: Response, db: Session = Depends(get_db)):
user = crud.get_user_by_email(db, request.email)
if not user or not verify_password(request.password, user.hashed_pw):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="이메일 또는 비밀번호가 올바르지 않습니다."
)
token = create_access_token(data={"sub": str(user.id)})
response.set_cookie(
key="access_token",
value=token,
httponly=True,
secure=False,
samesite="lax",
max_age=60 * 30,
path="/"
)
return {"access_token": token, "token_type": "bearer"}
라우터 등록
- app/main.py
from fastapi import FastAPI
from .routers import user, post, auth
app = FastAPI()
# 라우터 등록
app.include_router(user.router)
app.include_router(post.router)
app.include_router(auth.router)
테스트
- http://localhost:8000/docs 접속
- body에 email 과 password를 채워 넣은 후 테스트 실행
이후에 F12를 개발자 도구 진입 후 application - Cookies 항목에 토큰값이 보인다. 즉, 브라우저에 토큰 값이 저장 된다.
로그아웃 API 엔드포인트 구현
JWT 자체는 서버에 상태를 저장하지 않기 때문에 로그아웃은 클라이언트에서 토큰을 삭제하거나, 서버측에서 블랙리스트로 관리하는 방식으로 구현할수 있음
이번엔 쿠키 기반 로그아웃으로 클라이언트에서 토큰을 삭제하는 방식으로 할것이다.
- app/routers/auth.py
@router.post("/logout", summary="로그아웃")
def logout(response: Response):
response.delete_cookie(
key="access_token",
path="/",
)
return {"message": "로그아웃 완료"}
테스트
쿠키값이 사라진것을 확인할수 있다.
'WEB 개발' 카테고리의 다른 글
[JWT] JWT 토큰 이란? (0) | 2025.06.01 |
---|---|
[FastAPI] CRUD API 구현 (SQLAlchemy, RESTful API) (0) | 2025.05.27 |
REST, REST API, RESTful API (0) | 2025.05.20 |