728x90
1. auth.py에 새로운 클래스 추가
class LoginForm:
def __init__(self, request: Request):
self.request: Request = request
self.username: Optional[str] = None
self.password: Optional[str] = None
async def create_oauth_form(self):
form = await self.request.form()
self.username = form.get("email")
self.password = form.get("password")
await는 async 함수 안에서만 동작하며(일반 함수에는 동작 X), await를 만나면 self.request.form()가 처리될 때까지 기다리며 처리가 완료되면 결과와 함께 남은 실행이 재개된다.
self.request.form()이 처리되길 기다리는 동안엔 엔진이 다른 일(다른 스크립트를 실행, 이벤트 처리 등)을 할 수 있기 때문에, CPU 리소스가 낭비되지 않는다.
2. auth.py의 login_for_access_token API 수정
# 추가
from fastapi import Response
@router.post("/token")
async def login_for_access_token(response: Response, form_data: OAuth2PasswordRequestForm = Depends(),
db: Session = Depends(get_db)):
user = authenticate_user(form_data.username, form_data.password, db)
if not user:
raise False
token = create_access_token(user.username,
user.id,
expires_delta = timedelta(minutes=60))
response.set_cookie(key="access_token", value=token, httponly=True)
return True
쿠키는 브라우저에 데이터를 저장하기 위한 수단 중 하나
set_cookie는 response가 따라와야 하면 쿠기를 설정하기 위한 함수다.
httponly는 브라우저에서 쿠키값에 대한 접근을 하지 못하게 막는다.
3. auth.py에 로그인 API 생성
@router.post("/", response_class=HTMLResponse)
async def login(request: Request, db: Session = Depends(get_db)):
try:
form = LoginForm(request)
await form.create_oauth_form()
response = RedirectResponse(url="/todos", status_code=status.HTTP_302_FOUND)
validate_user_cookie = await login_for_access_token(response=response, form_data=form, db=db)
if not validate_user_cookie:
msg = "Incorrect Username or Password"
return templates.TemplateResponse("login.html", {"request": request, "msg": msg})
return response
except HTTPException:
msg = "Unknown Error"
return templates.TemplateResponse("login.html", {"request":request, "msg": msg})
4. login.html method 값 수정
{% include 'layout.html' %}
<div class="container">
<div class="card">
<!--상단타이틀-->
<div class="card-header">
Login
</div>
<div class="card-body">
<form method="POST" action="/auth" ...>
</div>
<!--회원가입-->
<div class="card-footer text-muted">
<a href="#"> Register? </a>
</div>
</div>
</div>
method = "POST"로 action은 /auth일 경우
5. 웹에서 Login 해보기
JWT 토큰이 어플리케이션 내에서 쿠키로 저장되는 것을 확인
어플리케이션 확인: 개발자도구(F12) -> Application -> Cookies
6. 잘못된 사용자 로그인
잘못된 로그인을 했을 때 Internal Server Error가 아닌 로그인 페이지로 가야 한다.
login_for_access_token API의 raise값을 return으로 바꿔준다.
@router.post("/token")
async def login_for_access_token(response: Response, form_data: OAuth2PasswordRequestForm = Depends(),
db: Session = Depends(get_db)):
user = authenticate_user(form_data.username, form_data.password, db)
if not user:
return False
token = create_access_token(user.username,
user.id,
expires_delta = timedelta(minutes=60))
response.set_cookie(key="access_token", value=token, httponly=True)
return True
잘못된 사용자에 대한 메시지를 띄운다.
login.html 알럿 추가
{% include 'layout.html' %}
<div class="container">
<div class="card">
<!--상단타이틀-->
<div class="card-header">
Login
</div>
<div class="card-body">
{% if msg %}
{% if msg == 'Logout Successful' or msg == 'User Successfully created' %}
<div class="alert alert-success" role="alert">
{{msg}}
</div>
{% else %}
<div class="alert alert-danger" role="alert">
{{msg}}
</div>
{% endif %}
{% endif %}
<form method="POST" action="/auth"...>
</div>
<!--회원가입-->
<div class="card-footer text-muted">
<a href="#"> Register? </a>
</div>
</div>
</div>
bootstrap.css의 alert을 이용을 해서 메시지창을 띄운다.
728x90
SMALL
'Develop > FastAPI' 카테고리의 다른 글
FastAPI 프로젝트 진행(로그아웃 기능 구현) - 92 (0) | 2023.01.29 |
---|---|
FastAPI 프로젝트 진행(로그인 추가, 쿠키 세션) - 91 (0) | 2023.01.29 |
FastAPI 프로젝트 진행(완료 버튼 작동, RedirectResponse) - 89 (0) | 2023.01.29 |
FastAPI 프로젝트 진행(데이터 삭제 API, RedirectResponse) - 88 (0) | 2023.01.29 |
FastAPI 프로젝트 진행(데이터 수정 API, RedirectResponse) - 87 (0) | 2023.01.29 |