FrameWork/FastAPI

회원가입

mansoorrr 2024. 6. 20. 22:56

회원가입, 로그인, 로그아웃은 웹페이지에서 가장 중요한 부분중에 하나. 이거 할줄알면 다 안다고도 할 수 있음.

 

[ User model 만들기 ]

  • User테이블이 많은 정보를 갖게 할 수 있지만 딱 필요한 정보만 가져오려 함
  • User테이블은 id, username, password, email 네가지 변수를 갖는다고 정의
  • 모델 정의 후 > alembic revision --autogenerate > alembic upgrade heade
// models.py

class User(Base):
	__tablename__= "user"
	id = Column(Integer, primary_key=True) #pk
	username = Column(String, nullable=False, unique=True)
	password = Column(String, nullable=False)
	email = Column(String, nullable=False, unique=True)

 

 

[Navigation Bar 수정 및 회원가입 Component 생성]

1. Navigation Bar 수정

  • Navigation.Svelte에 회원가입, 로그인 버튼 만들어줌
  • use:link를 이용해 동적 페이지 지정
<script>
	import {link} from 'svelte-spa-router';
</script>

<...생략...>

<span class="nav-button">
	//프론트상의 dom경로 지정
    <a use:link href="/user-create">회원가입</a>
</span>
<span class="nav-button">
	//프론트상의 dom경로 지정
    <a use:link href="/login">로그인</a>
</span>

 

2. UserCreate Component 생성

  • localhost:5173/#/user-create로 이동했을때 보여질 화면 생성
  • User모델과 달리 회원가입시에는 사용자이름, 비밀번호, 비밀번호확인, 이메일을 입력하게 함
<script>
	import {link} from 'svelte-spa-router';
	import {push} from 'svelte-spa-router';
	import fastapi from '../lib/api';
	import Error from '../components/Error.svelte';
	
	//화면을 통해 받을 값들 변수초기화
	let username = '';
	let password1 = '';
	let password2 = '';
	let email = '';
	let error = {detail:[]};
	
    //회원가입 버튼 눌렀을때 실행될 함수
	function postUser(event) {		
		event.preventDefault();

		const url = '/api/user/create';
		
		let params = {
			"username": username,
			"password1": password1,
			"password2": password2,
			"email": email,
		}

		fastapi('post', url, params,
			(json) => {				
				push('/')
				error = {detail:[]}
			},
			(json_error) => {
				error = json_error
			}
		)
	}
	
</script>

<div class="container">
	<h3 class="border-bottom mt-3 py-3">회원가입</h3>
	
 	// 에러컴포넌트
	<Error error={error}/> 

	<form action="post">
		<div class="mb-3">
			<label for="username">이름</label>
			<input type="text" class="form-control" bind:value={username}>
		</div>
		<div class="mb-3">
			<label for="password1">비밀번호</label>
			<input type="text" class="form-control" bind:value={password1}>
		</div>
		<div class="mb-3">
			<label for="password2">비밀번호 확인</label>
			<input type="text" class="form-control" bind:value={password2}>
		</div>
		<div class="mb-3">
			<label for="email">이메일</label>
			<input type="text" class="form-control" bind:value={email}>
		</div>
	</form>
	<button class="btn btn-dark" on:click={postUser}>회원가입</button>
	<a use:link href="/" class="btn btn-secondary">취소</a>
</div>

 

 

[App.svelte에 회원가입Component추가]

  • 만든 UserCreate.svelte를 App에 등록하여 라우팅 시 나타날 수 있도록 함
// App.svelte

<script>
    import UserCreate from "./routes/UserCreate.svelte";
    import Login from "./routes/Login.svelte";
</script>

const routes = {
  "/": Home,
  "/detail/:question_id": Detail,
  "/question-create": QuestionCreate,
  "/user-create": UserCreate, //추가
  "/login": Login, //추가
}

/user-create경로로 들어간 화면

 

[router 만들기 및 main에 등록]

  • prefix=/api/user로 설정, routing은 /create로 설정
  • 회원가입 정보는 post로 들어와야 함(보안문제)
  • post를 통해 front에서 back으로 데이터를 보내기 위해서는 form을 거쳐야 함
  • 이를 위해 user_schema.py에 UserCreate클래스(폼)를 만들어 적용
  • UserCreate클래스의 유효성 검사
    • 빈값입력할 경우 안되게: @field_validator 사용 > not_empty()
    • 비밀번호 1과 2가 같은지 검사: password_match()
#---------- domain/user/user_shcema.py

from pydantic import BaseModel, EmailStr, field_validator
from pydantic_core.core_schema import FieldValidationInfo
from sqlalchemy import ValuesBase

# 화면에서 전달된 값이 아래 스키마를 통해 유효성 검사가 됨
class UserCreate(BaseModel):
	username: str
	password1: str
	password2: str
	email: EmailStr

	# 빈값 안됨
	@field_validator('username', 'password1', 'password2', 'email')
	def not_empty(cls, v):
		if not v or not v.strip():
			raise ValueError('빈값은 안되요')
		return v

	#비밀번호1과 비밀번호2 같은지 유효성 검사
	@field_validator("password2")
	def password_match(cls, v, info: FieldValidationInfo):
		if "password1" in info.data and v != info.data['password1']:
			raise ValueError('비밀번호가 일치하지 않습니다')
		return v
    

# ---------- domain/user/user_router.py

from fastapi import APIRouter
from domain.user import user_schema

router = APIRouter(prefix="/api/user")

@router.post('/create')
def user_create(user_create:user_schema.UserCreate, # 위에서 만든 녀석이 여기 들어감
				db:Session=Depends(get_db),
				):
    # user객체를 만들때 폼(스키마)에서 유효성 검사를 마친 데이터가 사용됨
    user = User(username=user_create.username, pasasword=user_ceate.password, email=user_create.email)
    db.add(user)
    db.commit()


#---------- main.py
app.include_router(user_router.router) #user

 

 

[구동확인]

좌: 유효성검사 결과 에러로 송출 / 우: 회원가입 정상 구동