ํ”„๋กœ์ ํŠธ

์ผ๋ฐ˜

์‚ฌ์šฉ์ž์ •๋ณด

Actions

์ƒˆ๊ธฐ๋Šฅ #50

์ง„ํ–‰์ค‘

์ƒˆ๊ธฐ๋Šฅ #44: ๐Ÿ“˜ Mangement Cloud server FastAPI ํ”„๋กœ์ ํŠธ

๐ŸŸฅ Epic 1 - Task (Login) ๐Ÿ” FastAPI ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„

minkyu park์ด(๊ฐ€) 20์ผ ์ „์— ์ถ”๊ฐ€ํ•จ.

์ƒํƒœ:
์‹ ๊ทœ
์šฐ์„ ์ˆœ์œ„:
๋ณดํ†ต
๋‹ด๋‹น์ž:
์‹œ์ž‘์ผ:
2026/10/01
์™„๋ฃŒ์ผ:
์ง„์ฒ™๋„:

0%

์ถ”์ •์‹œ๊ฐ„:

์„ค๋ช…

๐ŸŸฅ Epic 1 โ€” Task (Login)

๐Ÿ” FastAPI ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„

๐Ÿ“Œ ์ž‘์—… ๊ฐœ์š”

mgmt ์„œ๋ฒ„์— ์ ‘๊ทผํ•˜๋Š” ๋ชจ๋“  ๊ธฐ๋Šฅ(์„œ๋ฒ„ ์ƒํƒœ ์กฐํšŒ, ์ œ์–ด, reverse SSH ๋“ฑ)์€

์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ FastAPI ๊ธฐ๋ฐ˜์˜ JWT ๋กœ๊ทธ์ธ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜์—ฌ

API ์ ‘๊ทผ์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณดํ˜ธํ•˜๋Š” ์ธ์ฆ ๋ ˆ์ด์–ด๋ฅผ ๋งŒ๋“ ๋‹ค.

์ด ์ž‘์—…์€ ์ „์ฒด ์‹œ์Šคํ…œ์˜ ๋ณด์•ˆ ๊ธฐ๋ฐ˜์ด ๋˜๋Š” ํ•ต์‹ฌ ๋‹จ๊ณ„์ด๋‹ค.

๐ŸŽฏ ์ž‘์—… ๋ชฉ์ 

  • FastAPI์—์„œ JWT ๊ธฐ๋ฐ˜ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค.

  • /login ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

  • ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ํ•ด์‹œ(SHA256 ๋˜๋Š” bcrypt)๋กœ ์ €์žฅํ•œ๋‹ค.

  • ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ Access Token(JWT)์„ ๋ฐœ๊ธ‰ํ•œ๋‹ค.

  • ์ดํ›„ ๋ชจ๋“  API์—์„œ Authorization: Bearer ๋ฐฉ์‹์œผ๋กœ ์ธ์ฆ์„ ์ ์šฉํ•œ๋‹ค.

๐Ÿ› ๏ธ ์ง„ํ–‰ ๋‚ด์šฉ

๐Ÿ—‚๏ธ 1. ์‚ฌ์šฉ์ž ๋ชจ๋ธ ์ƒ์„ฑ (app/models/user.py)

๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ์œ„ํ•ด ์‚ฌ์šฉ์ž ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•œ๋‹ค.

# app/models/user.py

from sqlalchemy import Column, String
from app.db import Base

class User(Base):
    __tablename__ = "user"

    username = Column(String(50), primary_key=True)
    password_hash = Column(String(200))

๐Ÿ“Œ ์„ค๊ณ„ ํฌ์ธํŠธ

  • ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ์ ˆ๋Œ€ ํ‰๋ฌธ ์ €์žฅ ๊ธˆ์ง€

  • username์„ PK๋กœ ์„ค์ •ํ•˜์—ฌ ๊ฐ„๋‹จํ•œ ์ธ์ฆ ๊ตฌ์กฐ ์œ ์ง€

๐Ÿ—‚๏ธ 2. ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹œ ์œ ํ‹ธ ์ƒ์„ฑ (app/core/security.py)

# app/core/security.py

import hashlib

def hash_password(password: str) -> str:
    return hashlib.sha256(password.encode()).hexdigest()

def verify_password(password: str, hashed: str) -> bool:
    return hash_password(password) == hashed

๐Ÿ“Œ bcrypt๋กœ ๋ฐ”๊ฟ€ ์ˆ˜๋„ ์žˆ์ง€๋งŒ

Park mgmt ์„œ๋ฒ„๋Š” ๋‚ด๋ถ€์šฉ์ด๋ผ SHA256๋„ ์ถฉ๋ถ„ํ•จ.

๐Ÿ—‚๏ธ 3. JWT ํ† ํฐ ๋ฐœ๊ธ‰ ๊ธฐ๋Šฅ ์ƒ์„ฑ (app/core/jwt.py)

# app/core/jwt.py

from datetime import datetime, timedelta
from jose import jwt

SECRET_KEY = "park-secret-key"
ALGORITHM = "HS256"

def create_access_token(username: str):
    expire = datetime.utcnow() + timedelta(hours=12)
    payload = {"sub": username, "exp": expire}
    return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)

๐Ÿ“Œ 12์‹œ๊ฐ„ ํ† ํฐ

๐Ÿ“Œ HS256

๐Ÿ“Œ jose ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ

๐Ÿ—‚๏ธ 4. ๋กœ๊ทธ์ธ API ์ƒ์„ฑ (app/routers/auth.py)

# app/routers/auth.py

from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.orm import Session

from app.db import SessionLocal
from app.models.user import User
from app.core.security import verify_password
from app.core.jwt import create_access_token

router = APIRouter()

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

@router.post("/login")
def login(username: str, password: str, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.username == username).first()

    if not user or not verify_password(password, user.password_hash):
        raise HTTPException(status_code=401, detail="Invalid credentials")

    token = create_access_token(username)
    return {"access_token": token, "token_type": "bearer"}

๐Ÿ—‚๏ธ 5. main.py์— ๋ผ์šฐํ„ฐ ๋“ฑ๋ก

from fastapi import FastAPI
from app.routers import auth

app = FastAPI()
app.include_router(auth.router)

๐Ÿ—‚๏ธ 6. test_main.http๋กœ ๋กœ๊ทธ์ธ ํ…Œ์ŠคํŠธ

### Login Test
POST http://127.0.0.1:8000/login
Content-Type: application/json

{
  "username": "admin",
  "password": "1234"
}

๐Ÿ“Œ ์‚ฐ์ถœ๋ฌผ

  • ์‚ฌ์šฉ์ž ๋ชจ๋ธ ์ƒ์„ฑ (user.py)

  • ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹œ ๊ธฐ๋Šฅ (security.py)

  • JWT ๋ฐœ๊ธ‰ ๊ธฐ๋Šฅ (jwt.py)

  • /login API ๊ตฌํ˜„

  • test_main.http๋กœ ๋กœ๊ทธ์ธ ํ…Œ์ŠคํŠธ ์™„๋ฃŒ

  • ์ธ์ฆ ๊ธฐ๋ฐ˜ ๊ตฌ์ถ• ์™„๋ฃŒ

ํ‘œ์‹œํ•  ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

Actions

๋‚ด๋ณด๋‚ด๊ธฐ Atom PDF