728x90
Authentication Routing / Todo Routing / Prefix Routing / External Routing / Dependencies Routing
1. 라우팅 역할
- 애플리케이션의 구조를 위한 유연한 도구
- 확장 가능 한 아키텍처를 지원
- 파일 구조화를 도움
2. 구성할 프로젝트 구조
TodoApp | ||||
main.py database.py models.py |
TodoApp/routers | TodoApp/company | ||
auth.py | todos.py | companyapis.py | dependencies.py |
인증 라우팅
TodoApp 디렉터리 내에 routers 디렉터리 생성
auth.py >> routers로 이동
auth.py 파일 수정
#경로 함수 삽입
import sys
sys.path.append('..')
# FastAPI 삭제, APITRouter 삽입
#from fastapi import FastAPI, Depends, HTTPException, status
from fastapi import Depends, HTTPException, status, APIRouter
from pydantic import BaseModel
from typing import Optional
import models
from passlib.context import CryptContext
from sqlalchemy.orm import Session
from database import SessionLocal, engine
from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer
from datetime import datetime, timedelta
from jose import jwt, JWTError
SECRET_KEY = "SECRE_KEY"
ALGORITHM = "HS256"
class CreateUser(BaseModel):
username: str
email: Optional[str]
first_name: str
last_name: str
password: str
bcrypt_context = CryptContext(schemes=['bcrypt'], deprecated="auto")
models.Base.metadata.create_all(bind=engine)
oauth2_bearer = OAuth2PasswordBearer(tokenUrl="token")
#app >> router
#app = FastAPI()
router = APIRouter()
def get_db():
try:
db = SessionLocal()
yield db
finally:
db.close()
def get_password_hash(password):
return bcrypt_context.hash(password)
def verify_password(plain_password, hashed_password):
return bcrypt_context.verify(plain_password, hashed_password)
def authenticate_user(username: str, password: str, db):
user = db.query(models.Users).filter(models.Users.username == username).first()
if not user:
return False
if not verify_password(password, user.hashed_password):
return False
return user
def create_access_token(username: str, user_id: int, expires_delta: Optional[timedelta] = None):
encode = {"sub": username, "id": user_id}
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
encode.update({"exp": expire})
return jwt.encode(encode, SECRET_KEY, algorithm=ALGORITHM)
async def get_current_user(token: str = Depends(oauth2_bearer)):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
user_id: int = payload.get("id")
if username is None or user_id is None:
raise get_user_exception()
return {"username": username, "id": user_id}
except JWTError:
return get_user_exception()
#app >> router
#@app.post("/create/user")
@router.post("/create/user")
async def create_new_user(create_user: CreateUser, db: Session = Depends(get_db)):
create_user_model = models.Users()
create_user_model.email = create_user.email
create_user_model.username = create_user.username
create_user_model.first_name = create_user.first_name
create_user_model.last_name = create_user.last_name
hash_password = get_password_hash(create_user.password)
create_user_model.hashed_password = hash_password
create_user_model.is_active = True
db.add(create_user_model)
#db.flush()
db.commit()
#app >> router
#@app.post("/token")
@router.post("/token")
async 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:
return token_exception()
token_expires = timedelta(minutes=20)
token = create_access_token(user.username,
user.id,
expires_delta=token_expires)
return {"token": token}
#Exceptions
def get_user_exception():
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate":"Bearer"},
)
return credentials_exception
def token_exception():
token_exception_response = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate":"Bearer"},
)
return token_exception_response
main.py 수정
from typing import Optional
from fastapi import FastAPI, Depends, HTTPException
import models
from database import engine, SessionLocal
from sqlalchemy.orm import Session
from pydantic import BaseModel, Field
#TodoApp 삭제
#from TodoApp.routers.auth import get_current_user, get_user_exception
from routers.auth import get_current_user, get_user_exception
#auth.py 가져오기
from routers import auth
app = FastAPI()
models.Base.metadata.create_all(bind=engine)
#router 추가
app.include_router(auth.router)
def get_db():
try:
db = SessionLocal()
yield db
finally:
db.close()
class Todo(BaseModel):
title: str
description: Optional[str]
priority: int = Field(gt=0, lt=6, description="The priority must be between 1-5")
complete: bool
@app.get("/")
async def read_all(db: Session = Depends(get_db)):
return db.query(models.Todos).all()
@app.get("/todos/user")
async def read_all_by_user(user: dict = Depends(get_current_user), db: Session = Depends(get_db)):
if user is None:
raise get_user_exception()
return db.query(models.Todos).filter(models.Todos.owner_id == user.get("id")).all()
@app.post("/")
async def create_todo(todo: Todo, user: dict = Depends(get_current_user), db: Session = Depends(get_db)):
if user is None:
raise get_user_exception()
todo_model = models.Todos()
todo_model.title = todo.title
todo_model.description = todo.description
todo_model.priority = todo.priority
todo_model.complete = todo.complete
todo_model.owner_id = user.get("id")
db.add(todo_model)
# db.flush()
db.commit()
return successful_response(200)
@app.put("/{todo_id}")
async def update_todo(todo_id: int,
todo: Todo,
user: dict = Depends(get_current_user),
db: Session = Depends(get_db)):
if user is None:
raise get_user_exception()
todo_model = db.query(models.Todos)\
.filter(models.Todos.id == todo_id)\
.filter(models.Todos.owner_id == user.get("id")).first()
if todo_model is None:
raise http_exception()
todo_model.title = todo.title
todo_model.description = todo.description
todo_model.priority = todo.priority
todo_model.complete = todo.complete
db.add(todo_model)
# db.flush()
db.commit()
return successful_response(200)
@app.get("/todo/{todo_id}")
async def read_todo(todo_id: int, user:dict = Depends(get_current_user), db: Session = Depends(get_db)):
if user is None:
raise get_user_exception()
todo_model = db.query(models.Todos).filter(models.Todos.id == todo_id).filter(models.Todos.owner_id == user.get("id")).first()
if todo_model is not None:
return todo_model
raise http_exception()
@app.delete("/{todo_id}")
async def delete_todo(todo_id: int, user: dict = Depends(get_current_user), db: Session = Depends(get_db)):
if user is None:
raise get_user_exception()
todo_model = db.query(models.Todos)\
.filter(models.Todos.id == todo_id)\
.filter(models.Todos.owner_id == user.get("id")).first()
if todo_model is None:
raise http_exception()
db.query(models.Todos).filter(models.Todos.id == todo_id).delete()
# db.flush()
db.commit()
return successful_response(200)
def successful_response(status_code:int):
return {
'status': status_code,
'transaction': 'Successful'
}
def http_exception():
return HTTPException(status_code=404, detail="Todo not found")
728x90
SMALL
'Develop > FastAPI' 카테고리의 다른 글
FastAPI Prefix 라우팅 - 66 (0) | 2023.01.17 |
---|---|
FastAPI Todo 라우팅(main.py 수정) 확장성 확인 - 65 (0) | 2023.01.17 |
FastAPI Create Data for MySQL - 63 (0) | 2023.01.15 |
FastAPI Connect FastAPI to MySQL - 62 (0) | 2023.01.15 |
FastAPI Mysql Create Database Tables - 61 (0) | 2023.01.15 |