Fastapi密码
1. 密码哈希:保护用户密码不被泄露
- 为什么需要哈希?
如果把密码直接存成明文(比如“123456”),一旦数据库被黑客窃取,所有密码都会暴露。
哈希就是把密码转换成一段乱码(比如“$2b\(12\)...”),且无法反向还原。即使数据库泄露,黑客也无法知道原始密码。 - 如何实现?
使用Passlib库和 Bcrypt 算法: - 存储密码时:输入明文密码 → 生成哈希值(如
get_password_hash("密码"))。 - 验证密码时:输入明文密码 → 与数据库中的哈希值对比(如
verify_password(输入的密码, 哈希值))。
2. JWT 令牌:安全传递用户身份
-
什么是 JWT?
JWT(JSON Web Token)是一个加密的“通行证”,包含用户信息(如用户名、过期时间等),并用密钥签名。 -
内容不可篡改:如果有人修改了令牌,服务器会通过签名发现并拒绝它。
-
有效期:比如设置令牌 30 分钟后过期,过期后需重新登录获取新令牌。
-
如何生成和验证?
使用PyJWT库: -
生成令牌:用户登录成功后,用密钥(
SECRET_KEY)生成 JWT,返回给用户。create_access_token(data={"sub": "用户名"}, expires_delta=30分钟)-
验证令牌:用户每次请求时携带令牌,服务器解码并校验签名是否合法、是否过期。
# 验证逻辑:尝试解码 → 检查签名 → 获取用户名 → 查询用户是否存在
-
3. OAuth2 流程:用户登录与权限验证
- 登录流程(/token 端点):
-
用户发送用户名和密码到
/token接口。 -
服务器用哈希比对密码是否正确。
-
若正确,生成 JWT 令牌并返回给用户。
{"access_token": "xxx...", "token_type": "bearer"}
- 后续请求验证:
用户在请求头中携带令牌(如Authorization: Bearer xxx...)。
服务器通过依赖项get_current_user验证令牌:
- 解码令牌,检查签名和过期时间。
- 提取用户名,查询数据库确认用户存在且未被禁用。
- 若通过,返回用户信息供接口使用。
4. 关键代码流程
用户登录(获取令牌)
@app.post("/token")
async def login_for_access_token(form_data: OAuth2PasswordRequestForm):
# 1. 验证用户名和密码(密码哈希比对)
user = authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=401, detail="用户名或密码错误")
# 2. 生成 JWT 令牌
access_token = create_access_token(data={"sub": user.username})
return {"access_token": access_token, "token_type": "bearer"}
验证当前用户
async def get_current_user(token: str = Depends(oauth2_scheme)):
try:
# 1. 解码 JWT 令牌,获取用户名
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
# 2. 查询用户是否存在
user = get_user(username)
if not user:
raise HTTPException(status_code=401, detail="无效用户")
except:
raise HTTPException(status_code=401, detail="令牌无效")
return user
5. 总结
- 密码哈希:保护密码不被泄露,用
Passlib处理。 - JWT 令牌:安全传递用户身份,用
PyJWT生成和验证。 - OAuth2 流程:用户登录获取令牌 → 后续请求携带令牌 → 服务器验证令牌合法性。
通过这些步骤,用户可以安全地登录并访问受保护的接口,同时避免了明文密码存储和频繁输入密码的麻烦。
1. JWT 是什么?
JWT(全称 JSON Web Token)是一种 轻量级的、用于在客户端和服务器之间传递信息 的技术。它的核心作用是 身份验证和信息传递,比如登录后保持用户状态、在不同服务间传递用户信息等。
举个例子:
想象你去餐厅吃饭,服务员给你一张写着“已付款”的纸条。这张纸条就是你的“通行证”,你可以凭它去取餐、续杯,而服务员不需要每次都重新核对你的身份。
JWT 就像这张纸条,但它是用加密的方式生成的,只有特定的人(服务器)才能验证它的有效性。
2. JWT 的结构
JWT 由三部分组成,用点号(.)分隔,格式是:
header.payload.signature
(1) Header(头部)
-
内容:通常包含两样东西:
- 算法(比如
HS256,一种加密算法)。 - 类型(固定是
JWT)。
- 算法(比如
-
例子:
{ "alg": "HS256", "typ": "JWT" } -
作用:告诉服务器如何处理这个 Token。
(2) Payload(载荷)
-
内容:存储用户信息和声明(claims),比如:
- 用户 ID、用户名、过期时间(
exp)、权限等。
- 用户 ID、用户名、过期时间(
-
例子:
{ "user_id": 123, "username": "Alice", "exp": 1704076800 // 过期时间(Unix 时间戳) } -
作用:传递用户身份和权限等信息。
(3) Signature(签名)
-
内容:用 Header 和 Payload 的内容,加上一个 密钥(只有服务器知道),通过算法(比如
HS256)生成的字符串。 -
作用:验证 Token 是否被篡改过,确保可信。
3. JWT 的工作流程
假设你登录了一个网站,以下是 JWT 的工作流程:
步骤 1:登录验证
-
你输入用户名和密码,服务器验证成功后,生成一个 JWT。
-
服务器把 JWT 返回给你,你保存在浏览器或 App 中。
步骤 2:携带 Token 访问其他页面
-
你访问其他页面时,浏览器自动在请求头中带上这个 JWT(比如放在
Authorization字段):Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...步骤 3:服务器验证 Token
-
服务器收到请求后,会做以下检查:
-
验证签名:用同样的算法和密钥,重新生成签名,对比是否一致。如果不同,说明 Token 被篡改过。
-
检查过期时间:如果
exp已过期,拒绝请求。 -
解析 Payload:获取用户信息(比如用户 ID、权限)。
步骤 4:处理请求
-
-
如果验证通过,服务器就按照你的身份和权限处理请求(比如显示用户信息、允许编辑内容等)。
4. 为什么用 JWT?
优点:
-
无状态(Stateless):服务器不需要记录用户登录状态(比如 Session),减轻服务器负担。
-
跨域友好:适合移动端、单页应用(SPA)等场景。
-
可扩展:可以在 Payload 中添加任意信息(只要不敏感)。
缺点:
-
信息可见:Payload 是明文(Base64 编码),虽然不可篡改,但可以被读取。不要在 Payload 中存储敏感信息(比如密码、银行卡号)。
-
无法撤销:一旦 Token 发出,除非过期,否则无法主动撤销。如果需要紧急下线用户,可能需要其他手段(比如黑名单)。
5. 生活中的类比
想象你去一个需要门票的游乐场:
- 门票(JWT):由入口处的工作人员(服务器)发放。
- 门票内容:
- Header:门票类型(比如“一日票”)、编码方式。
- Payload:你的姓名、入场时间、有效期。
- Signature:工作人员盖的章,确保门票真实有效。
- 使用流程:
- 你买票后拿到门票(登录成功后获得 JWT)。
- 每次进入游乐场时,工作人员扫描门票(服务器验证 Token)。
- 如果门票过期或被篡改,工作人员会拒绝你。
总结
JWT 是一种轻量级、安全的 Token 机制,用于在客户端和服务器之间传递用户身份和信息。它通过加密签名确保数据可信,适合现代 Web 应用的无状态架构。但要注意,Payload 是可见的,不要存储敏感数据,且无法主动撤销。

浙公网安备 33010602011771号