FrameWork/FastAPI

current user(OAuth2PasswordBearer)

mansoorrr 2024. 6. 21. 14:56

User모델을 추가 하였음으로 Question과 Answer모델에 user정보를 추가할 수 있다. 이것을 진행하기 위해 SQLite의 경우 별도로 진행하는 것이 있다(mysql, postgre등 다른 db들과는 무관).

 

3-09 글쓴이 저장하기

* `[완성 소스]` : [https://github.com/pahkey/fastapi-book/tree/v3.09](https://github.com/pahkey/fastapi…

wikidocs.net

 

1. Question, Answer모델 수정

  • user정보를 받을 수 있게 한다(user_id, user)
  • 모델에 코드 추가한 후 cmd에서 명령어 실행
    • alembic revision --autogenerate
    • alembic upgrade head
#---------- models.py

class Question(Base):
    __tablename__ = "question"
    id = Column(Integer, primary_key=True)
    subject = Column(String, nullable=False)
    content = Column(Text, nullable=False)
    create_date = Column(DateTime, nullable=False)
    user_id = Column(Integer, ForeignKey("user.id"), nullable=True) #추가
    user = relationship("User", backref="question_users") #추가
    
 
class Answer(Base):
	__tablename__ = "answer"
	id = Column(Integer, primary_key=True) #pk
	content = Column(String, nullable=True)
	create_date = Column(DateTime, nullable=True)
	question_id = Column(Integer, ForeignKey("question.id")) #fk
	question = relationship("Question", backref="answers") #backref
	user_id = Column(Integer, ForeignKey('user.id'), nullable=True) #추가
	user = relationship("User", backref='answer_users') #추가

 

 

2. 글쓴이 정보 받아오기

로그인시 사용자정보(이름, 토큰, 로그인여부)가 localStorage에 저장되었다. 이 저장된 정보를 사용하여 데이터를 처리하는 부분은 질문등록, 답변등록 이다. 아래와 같은 순서로 데이터를 처리한다.

  • 로그인시 localStorage저장
  • 백엔드 API호출시 header에 access_token을 포함하여 전달
  • 백엔드에서 전달받으면 access_token을 분석하여 사용자명 획득
  • 사용자명으로 뭔가 진행

[위의 순서를 처리하는 함수 생성]

#-------------------- user_router.py

from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer
from jose import jwt, JWTError

# '/api/user/login'에서 만들어진 토큰을 분석하는 스키마
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/user/login")

#로컬스토리지에 있는 정보로 user정보를 추출
def get_current_user(token:str=Depends(oauth2_scheme), # 스키마 적용된 토큰
					db:Session=Depends(get_db)
                    ):
	credentials_exception = HTTPException(
    	status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    
    #만들어진 토큰에서 username을 추출
    try:
        payload = jwt.decode(token, SECRET_KEY, ALGORITHM) #토큰을 디코딩
        username:str = payload.get('sub') #디코딩한 것에서 sub의 내용 추출(인코딩할때 sub에 사용자명이 들어있었으므로)
        if username is None:
            raise credentials_exception
    except JMTError:
    	raise credential_exception
    else:
        user = db.query(User).filter(User.username==username).first()
        if user is None:
            raise credentials_exception
        return user

 

[질문등록, 답변등록 api에 get_current_user적용]

# -------------------- question_router.py
from domain.user.user_router import get_current_user

@router.post('/create', status_code=status.HTTP_204_NO_CONTENT) 
def question_create(question_create:question_schema.QuestionCreate,
                    current_user:User=Depends(get_current_user), #추가
                    db: Session=Depends(get_db),
                    ):
	subject = question_create.subject
	content = question_create.content
	question = Question(
		subject = subject,
		content = content,
		create_date = datetime.now(),
		user = current_user #추가
	)
	db.add(question)
	db.commit()
    
    
# -------------------- answer_router.py
from domain.user.user_router import get_current_user

@router.post('/create/{question_id}', status_code=status.HTTP_204_NO_CONTENT)
def answer_create(answer_create:answer_schema.AnswerCreate,
                question_id:int,
                current_user: User=Depends(get_current_user), #추가
                db:Session=Depends(get_db),
                ):
	question = db.query(Question).get(question_id)
	content = answer_create.content
	answer = Answer(
    	content=content, 
        question=question, 
        create_date=datetime.now(), 
        user=current_user # 추가
    )
	db.add(answer)
	db.commit()

get_current_user적용 후 db모습