오늘날의 웹 애플리케이션은 사용자 인증이 필수적입니다. 사용자의 신원을 확인하고 보호하기 위해 다양한 인증 방법이 존재합니다. 본 포스트에서는 FastAPI를 사용하여 사용자 인증을 구현하는 방법에 대해 자세히 설명하겠습니다. FastAPI는 Python으로 쓰인 현대적인 웹 프레임워크로, 빠른 성능과 쉽게 사용할 수 있는 API 설계로 인기를 끌고 있습니다.
1. FastAPI 소개
FastAPI는 Python 3.6 이상에서 사용할 수 있으며, AsyncIO를 기반으로 비동기 프로그래밍을 지원합니다. 또한 자동 문서화 기능을 제공하여 Swagger UI 및 ReDoc을 통해 API 문서를 쉽게 생성할 수 있습니다. FastAPI는 Pydantic을 기반으로 데이터 검증 및 설정 관리를 효율적으로 처리합니다.
2. 사용자 인증의 중요성
사용자 인증은 사용자의 신원을 확인하고, 이를 기반으로 권한을 부여하는 과정입니다. 이는 다음과 같은 이유로 중요합니다:
- 보안성: 사용자 데이터 보호 및 유출 방지
- 접근 제어: 사용자에 따라 권한 부여 및 제한
- 사용자 경험: 개인화된 서비스 제공
3. FastAPI에서의 사용자 인증 기법
FastAPI에서 사용자 인증을 구현할 수 있는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 JWT (JSON Web Token)를 사용하는 것입니다. JWT는 사용자를 인증하고 정보를 안전하게 전송할 수 있는 토큰 기반 인증 방법입니다.
4. 필요한 라이브러리 설치
FastAPI와 JWT를 사용하기 위해 필요한 라이브러리를 설치합니다. 아래 명령어를 사용하여 필요한 패키지를 설치하세요:
pip install fastapi uvicorn python-jose passlib[bcrypt]
5. 기본 FastAPI 설정
FastAPI 애플리케이션을 설정합니다. 다음 코드를 사용하여 기본 FastAPI 애플리케이션을 만드세요:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def read_root():
return {"Hello": "World"}
6. 사용자 모델 및 데이터베이스 설정
이제 사용자 모델을 정의하고 데이터베이스에 연결합니다. SQLAlchemy를 사용하여 데이터베이스와의 상호작용을 간단하게 처리할 수 있습니다. 아래는 기본적인 사용자 모델 코드입니다:
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String, unique=True, index=True)
hashed_password = Column(String)
위 코드에서 사용자 모델을 정의했습니다. `username`과 `hashed_password`를 통해 기본적인 사용자 정보를 저장할 수 있습니다.
7. 비밀번호 해싱
사용자의 비밀번호를 안전하게 저장하기 위해 해싱을 사용합니다. Passlib 라이브러리를 사용하여 비밀번호를 해싱하고 검증할 수 있습니다:
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def get_password_hash(password):
return pwd_context.hash(password)
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
8. 사용자 추가 및 등록 엔드포인트
사용자를 등록할 수 있는 엔드포인트를 추가합니다. 사용자가 비밀번호를 안전하게 저장하도록 해싱 후 데이터베이스에 저장할 수 있습니다:
from fastapi import Depends, HTTPException
from sqlalchemy.orm import Session
Base.metadata.create_all(bind=engine)
# Create the user
@app.post("/users/")
def create_user(username: str, password: str, db: Session = Depends(get_db)):
hashed_password = get_password_hash(password)
db_user = User(username=username, hashed_password=hashed_password)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
9. JWT 토큰 생성
로그인 후 JWT 토큰을 생성하여 반환하는 엔드포인트를 추가합니다:
from datetime import datetime, timedelta
from jose import JWTError, jwt
SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
def create_access_token(data: dict, expires_delta: timedelta = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
10. 로그인 엔드포인트
사용자가 로그인할 수 있도록 엔드포인트를 추가합니다.
@app.post("/token")
async def login(username: str, password: str, db: Session = Depends(get_db)):
user = db.query(User).filter(User.username == username).first()
if not user or not verify_password(password, user.hashed_password):
raise HTTPException(status_code=400, detail="잘못된 사용자명 또는 비밀번호")
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(data={"sub": user.username}, expires_delta=access_token_expires)
return {"access_token": access_token, "token_type": "bearer"}
11. 보호된 엔드포인트 설정
JWT 토큰으로 보호된 엔드포인트를 설정합니다. 사용자가 인증된 경우에만 접근할 수 있도록 구현합니다:
from fastapi import Security, Depends
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
credentials_exception = HTTPException(status_code=401, detail="유효하지 않은 자격 증명", headers={"WWW-Authenticate": "Bearer"})
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = db.query(User).filter(User.username == username).first()
if user is None:
raise credentials_exception
return user
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
12. FastAPI 서버 실행
모든 설정이 완료되었으니, 이제 FastAPI 서버를 실행할 준비가 되었습니다. 아래 명령어로 서버를 실행하세요:
uvicorn main:app --reload
위 명령어를 통해 FastAPI 서버가 `http://127.0.0.1:8000`에서 실행됩니다.
13. Swagger UI를 통한 API 문서화
FastAPI는 Swagger를 통해 자동으로 API 문서를 생성합니다. 브라우저에서 `http://127.0.0.1:8000/docs`로 이동하면 API 문서를 확인할 수 있습니다.
14. 결론
FastAPI를 사용한 사용자 인증 구현 방법에 대해 알아보았습니다. 비밀번호 해싱, JWT 기반 인증을 포함한 사용자 등록 및 로그인 기능을 제공하는 API를 구축했습니다. FastAPI의 강력한 기능을 통해 효율적으로 사용자 인증을 처리할 수 있습니다.