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()
