개발로 자기계발
article thumbnail
728x90

프로젝트 디렉터리 구조

fastapi
todoapp
main.py

database.py

models.py

todos.db
templates static routers
todo
css js
home.html

add-todo.html

edit-todo.html

login.html

register.html

layout.html

navbar.html

edit-user-password.html
base.css

bootstrap.css
bootstrap.js

jquery-slim.js

popper.js
auth.py

todos.py

users.py
templates 하위에 edit-user-password.html 생성
routers 하위에 users.py 생성

 

1. users.py 기본 세팅

import sys
sys.path.append("..")

from starlette import status
from starlette.responses import RedirectResponse
from fastapi import Depends, APIRouter, Request, Form
import models
from database import engine, SessionLocal
from sqlalchemy.orm import Session
from pydantic import BaseModel
from .auth import get_current_user, verify_password, get_password_hash

from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates


router = APIRouter(
    prefix="/users",
    tags=["users"],
    responses={404: {"description": "Not Found"}}
)

models.Base.metadata.create_all(bind=engine)

templates = Jinja2Templates(directory="templates")

def get_db():
    try:
        db = SessionLocal()
        yield db
    finally:
        db.close()


class UserVerification(BaseModel):
    username: str
    password: str
    new_password: str
UserVerification 클래스: 파싱 and 유효성 검사
get_db 함수: DB 연결

 

2. users.py GET API 생성

@router.get("/edit-password", response_class=HTMLResponse)
async def edit_user_view(request: Request):

    user = await get_current_user(request)
    if user is None:
        return RedirectResponse(url="/auth", status_code=status.HTTP_302_FOUND)

    return templates.TemplateResponse("edit-user-password.html", {"request": request, "user": user})

 

3. navbar.html 수정

<div>
    <nav class="navbar navbar-expand-md navbar-dark main-color fixed-top">
        <a class="navbar-brand" href="#">Todo App</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
                aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav" ...>

           <ul class="navbar-nav ml-auto">
              {% if user %}
              
              <!--패스워드 수정 버튼 생성-->
              <li class="nav-item m-1">
                 <a type="button" class="btn btn-outline-light" href="/users/edit-password">Edit User</a>
              </li>
              <!--------------------->
              
              <li class="nav-item m-1" ...>
              
              {% endif %}
           </ul>
        </div>
    </nav>
</div>
navbar에 Edit User 버튼 생성

 

4. edit-user-password.html 수정

{% include 'layout.html' %}

<div class="container">
    <div class="card">

       <div class="card-header">
            Let's edit your Password!
        </div>

       <div class="card-body">
           {% if msg %}
             <div class="alert alert-danger" role="alert">
               {{msg}}
              </div>
         {% endif %}

            <form method="POST" action="/users/edit-password">
                <div class="form-group col-md-6">
                    <label>Username</label>
                    <input type="text" class="form-control" name="username" value="{{user.get('username')}}" required>
                </div>
                <div class="form-group col-md-6">
                    <label>Password</label>
                    <input type="password" class="form-control" name="password" required>
                </div>
               <div class="form-group col-md-6">
                    <label>New Password</label>
                    <input type="password" class="form-control" name="new_password" required>
                </div>
                <button type="submit" class="btn btn-primary">Edit</button>
            </form>

        </div>
    </div>
</div>
Username input칸에 기본적으로 쿠키에 저장된 username을 넣어준다.
 

 

5. users.py POST API 생성

@router.post("/edit-password", response_class=HTMLResponse)
async def user_password_change(request: Request, password: str = Form(...),
                               new_password: str = Form(...), db: Session = Depends(get_db)):


    user = await get_current_user(request)
    if user is None:
        return RedirectResponse(url="/auth", status_code=status.HTTP_302_FOUND)

    user_data = db.query(models.Users).filter(models.Users.username == user.get("username")).first()

    msg = "Incorrect Username or Password"

    if user_data is not None:
        if verify_password(password, user_data.hashed_password):
            user_data.hashed_password = get_password_hash(new_password)
            db.add(user_data)
            db.flush()
            db.commit()
            msg = "Password Updated Please Login Again"

            response = templates.TemplateResponse("login.html", {"request": request, "msg": msg})
            response.delete_cookie(key="access_token")
            return response

    return templates.TemplateResponse("edit-user-password.html", {"request": request, "msg": msg, "user": user})
verify_password: 패스워드 검사
user_data가 있다면 새로운 패스워드로 업데이트하고 로그인 페이지로 돌아가라(이때 쿠키는 삭제)
user_data가 없다면 새로운 패스워드로 업데이트 하지 말고 다시 패스워드 수정 페이지로 돌아가라

 

6. login.html 수정

{% include 'layout.html' %}

<div class="container">
    <div class="card">
       <!--상단타이틀-->
        <div class="card-header">
            Login
        </div>
        <div class="card-body">

           {% if msg %}
           <!-- Password Updated Please Login Again 조건 추가 -->
           {% if msg == 'Logout Successful' or msg == 'User Successfully created' or msg == 'Password Updated Please Login Again' %}
           <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" ...>
    </div>
</div>

 

7. 웹으로 비밀번호 변경하기

현재 비밀번호를 잘못 입력하면 에러 메세지가 발생하고 다시 입력해야 한다.

 

비밀번호가 변경되면 다시 로그인 페이지로 돌아오면서 쿠키값은 삭제가 된다.
비밀번호가 변경된 것을 확인하고 싶으면 pgAdmin4에 접속해서 hashed_password가 바뀐 것을 확인한다.
728x90
SMALL
profile

개발로 자기계발

@김잠봉

틀린부분이나 조언이 있다면 언제든 환영입니다:-)