<aside>
</aside>
μλ νμΈμ! λλμ΄ 6λΆ 'μΈμ¦ λ° λ³΄μ'μ 첫 λ²μ§Έ ꡬν μκ°, 28κ°μ λλ€! πβ¨
μ§λ 27κ°μμλ μΈμ¦(AuthN)κ³Ό μΈκ°(AuthZ)μ κ°λ μ λ°°μ°κ³ , OAuth2μ JWTλ₯Ό μ¬μ©νμ¬ μ°λ¦¬ ToDo APIμ λ‘κ·ΈμΈ κΈ°λ₯μ ꡬνν κ³νμ μΈμ μ΅λλ€.
λ‘κ·ΈμΈ κΈ°λ₯μ λ§λ€λ €λ©΄, λΉμ°ν λ¨Όμ μ¬μ©μκ° κ°μ ν μ μμ΄μΌκ² μ£ ? μ΄λ² μκ°μλ λ°λ‘ μ΄ μ¬μ©μ λ±λ‘(νμκ°μ ) APIλ₯Ό ꡬνν©λλ€. μ¬μ©μκ° μ΄λ©μΌκ³Ό λΉλ°λ²νΈλ₯Ό μ 곡νλ©΄, μ΄λ₯Ό λ°μ΄ν°λ² μ΄μ€μ μμ νκ² μ μ₯νλ λ‘μ§μ λ§λ€ κ±°μμ.
μ¬κΈ°μ κ°μ₯ μ€μν ν΅μ¬! μ¬μ©μμ λΉλ°λ²νΈλ₯Ό μ λλ‘ κ·Έλ₯ μ μ₯νλ©΄ μ λλ€λ κ²μ
λλ€! π
ββοΈ μ΄λ² μκ°μλ λΉλ°λ²νΈλ₯Ό μμ νκ² μ²λ¦¬νλ νμ€μ μΈ λ°©λ²μΈ **ν΄μ±(Hashing)**μ λν΄ λ°°μ°κ³ , Pythonμ passlib
λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ λΉλ°λ²νΈλ₯Ό ν΄μ±νκ³ κ²μ¦νλ ν¨μλ₯Ό ꡬνν©λλ€. κ·Έλ¦¬κ³ μ΄ ν¨μλ€μ νμ©νμ¬ μ¬μ©μ λ±λ‘ API(POST /users/
)λ₯Ό μμ±ν΄ λ³΄κ² μ΅λλ€.
μμ ν APIλ₯Ό ν₯ν 첫걸μ, ν¨κ» μμν΄λ΄ μλ€!
μ΄λ² 28κ°μμλ μ¬μ©μκ° μ°λ¦¬ μλΉμ€μ κ°μ
ν μ μλλ‘ μ¬μ©μ λ±λ‘ API μλν¬μΈνΈ(POST /users/
)λ₯Ό ꡬνν©λλ€. μ΄ κ³Όμ μμ μΉ μ ν리μΌμ΄μ
보μμ κ°μ₯ κΈ°λ³Έμ μ΄λ©΄μλ μ€μν μμΉμΈ μμ ν λΉλ°λ²νΈ μ²λ¦¬ λ°©λ²μ μ€μ μ μΌλ‘ λ€λ£Ήλλ€.
μ¬μ©μ λΉλ°λ²νΈλ₯Ό λ°μ΄ν°λ² μ΄μ€μ νλ¬Έ(plain text)μΌλ‘ μ μ₯νλ κ²μ μνμ±μ λ°°μ°κ³ , μ΄λ₯Ό ν΄κ²°νκΈ° μν **λΉλ°λ²νΈ ν΄μ±(Password Hashing)**μ κ°λ (λ¨λ°©ν₯ ν¨μ, μνΈ(Salt))μ μ΄ν΄ν©λλ€. νΉν, λΉλ°λ²νΈ ν΄μ±μ λ리 μ¬μ©λλ κ°λ ₯ν μκ³ λ¦¬μ¦μΈ Bcryptμ λν΄ μμλ΄ λλ€.
Pythonμμ λΉλ°λ²νΈ ν΄μ±μ μ½κ² μ²λ¦¬ν μ μλλ‘ λμμ£Όλ νμ€ λΌμ΄λΈλ¬λ¦¬μΈ **passlib
**λ₯Ό μ€μΉνκ³ μ¬μ©νλ λ°©λ²μ λ°°μλλ€. passlib
μ CryptContext
λ₯Ό μ€μ νκ³ , μ΄λ₯Ό μ΄μ©νμ¬ λΉλ°λ²νΈλ₯Ό ν΄μ±νλ ν¨μ(get_password_hash
)μ ν΄μλ λΉλ°λ²νΈλ₯Ό κ²μ¦νλ ν¨μ(verify_password
)λ₯Ό app/security.py
νμΌμ ꡬνν©λλ€.
λ§μ§λ§μΌλ‘, μ΄ ν΄μ± ν¨μλ€κ³Ό Pydantic μ
λ ₯ λͺ¨λΈ(UserCreate
), SQLAlchemy μΈμ
(AsyncSession
)μ ν¨κ» μ¬μ©νμ¬ μ¬μ©μ λ±λ‘ μλν¬μΈνΈ λ‘μ§μ μμ±ν©λλ€. μ΄ κ³Όμ μμ μ΄λ―Έ λ±λ‘λ μ΄λ©μΌμΈμ§ νμΈνλ μ€λ³΅ μ²΄ν¬ λ‘μ§λ ν¨κ» ꡬνν©λλ€.
μ΄ κ°μλ₯Ό λ§μΉλ©΄ μ¬λ¬λΆμ λ€μμ ν μ μκ² λ©λλ€:
passlib
λΌμ΄λΈλ¬λ¦¬(bcrypt
μ§μ ν¬ν¨)λ₯Ό μ€μΉνκ³ CryptContext
λ₯Ό μ€μ ν μ μμ΅λλ€.passlib
λ₯Ό μ¬μ©νμ¬ λΉλ°λ²νΈλ₯Ό ν΄μ±νλ ν¨μμ ν΄μλ₯Ό κ²μ¦νλ ν¨μλ₯Ό ꡬνν μ μμ΅λλ€. (app/security.py
)UserCreate
)μ μ μν μ μμ΅λλ€. (app/models/user.py
)