fastapi项目 03-注册,密码加密

发布时间 2023-12-28 14:08:13作者: dack_deng

1. 前沿

一般对于后端的接口,特别是注册接口而言,密码都不是明文存储的,而是通过加密的方式,存储加密后的密码的。

1.1 环境准备

我们需要下载第三方加密库:> pip install passlib
passlib 库里面会用到2个方法

  • encrypt() - 生成新的值,返回密码哈希
  • verify() - 根据现有哈希验证密码.
    Passlib是Python 2和3的密码散列库,它提供了30多种密码散列算法的跨平台实现,以及管理现有密码散列的框架。它被设计用于广泛的任务,从验证/etc/shadow中的散列,到为多用户应用程序提供全强度密码散列。
from passlib.hash import pbkdf2_sha256

password = "dack"  
hash_p = pbkdf2_sha256.hash("dack")  
print(f"加密后:{hash_p}")

我们多运行几次,发现每次得到的结果都不一样
加密后:$pbkdf2-sha256$29000$yBljbE3JGSPknHOu1VqrtQ$YN4k3VHR.lK1eUMrbrILP2JbIq0MkBArGvgCamaqG2c
加密后:$pbkdf2-sha256$29000$PkdIKcXYuxdizDkHIGQsRQ$XX5jghW9/Ez10fsIculxWX7PZ8A5upjx0cXs.2Wd7HE

这样就会让别人很难破解出你的原始密码内容,在数据库我们就可以保存加密后的值。当用户传一个密码值过来的时候,可以用verify() 方法验证密码是否正确。

# 验证密码
result1 = pbkdf2_sha256.verify("dack1", hash_p)
print(result1)
result2 = pbkdf2_sha256.verify("dack", hash_p)
print(result2)

# 运行结果
False
True

除了上面用到的pbkdf2_sha256 加密方式,它提供了30多种密码散列算法,使用方法都差不多,比如用sha256_crypt。

from passlib.hash import sha256_crypt

password = "dack"
hash_p = sha256_crypt.hash("dack")
print(f"加密后:{hash_p}")

# 验证密码
result1 = sha256_crypt.verify("dack1", hash_p)
print(result1)
result2 = sha256_crypt.verify("dack", hash_p)
print(result2)
# 运行结果:
加密后:$5$rounds=535000$BhJ3gP9aySdAmAdc$e5h9KJVtmmkhtT/W0RyoBsYrXChnC.aU7zLpaZV6X1B
False
True

2. models模型,对密码加密

# apps/model/models.py

    def hash_password(self, password: str):
        """密码加密"""
        self.password = sha256_crypt.encrypt(password)

    def verify_password(self, password: str):
        """校验密码"""
        return sha256_crypt.verify(password, self.password)

创建用户数据时,调用hash_password() 方法。

# apps/routers/view_login.py

from typing import Union
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field, EmailStr

class UserInfo(BaseModel):
    username: str = Field(..., title="用户名", description="用户名", min_length=3, max_length=10)
    password: str = Field(..., title="密码", description="密码", min_length=6, max_length=16)
    email: Union[EmailStr, None] = Field(default=None, title="邮箱")

@router.post("/register")
async def register_demo(body: UserInfo, db: Session = Depends(get_db)):
    # db的实例
    print(f"请求body:{body}")
    user = User(**body.dict())
    if db.query(User).filter(User.username == user.username).count():
        # 已被注册
        raise HTTPException(status_code=400, detail="username already exist")
    # 密码加密
    user.hash_password(user.password)
    print(f'数据入库前:{user.username}')

    db.add(user)
    db.commit()
    db.refresh(user)
    return {"code": 0000, "body": user}

运行main.py文件。通过postman进行测试是否密码加密成功。