一文掌握异步web框架FastAPI(六)-- 安全(HTTP验证、Bearer Token、Session、OAuth2 和 OpenID Connect、HTTPS 和 TLS、速率限制)

 目录

 

九、安全

1、HTTP 基本身份验证(Basic Authentication)

2、Bearer Token

3、Session 管理

1)简单实现

2)当需要session验证的接口会有多个时,使用中间件来做验证。

3)当有大量接口,其中一些需要登录而另一些不需要时,可以使用FastAPI的依赖注入系统来管理这些接口的访问控制。

4、OAuth2 和 OpenID Connect在fastapi中的应用

1)OAuth2

2)OpenID Connect

5、HTTPS 和 TLS 加密

1)获取 SSL/TLS 证书

自签名证书生成(仅用于开发测试)

2)配置 FastAPI 使用 HTTPS

3)配置 TLS 加密

4)生产环境部署建议

6、Rate Limiting (速率限制)


九、安全

1、HTTP 基本身份验证(Basic Authentication)

这是最简单的身份验证形式之一,它要求客户端发送带有用户名和密码的 HTTP 头部。FastAPI 可以很容易地集成这种身份验证方式。使用 hashlib 对密码进行哈希处理以提高安全性。

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from hashlib import sha256

app = FastAPI()
security = HTTPBasic()
# 假设我们存储的是密码的哈希值
STORED_USERNAME = "john"
STORED_PASSWORD_HASH = sha256("secret".encode()).hexdigest()


def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
    """获取当前用户名,并验证提供的凭据是否正确。"""
    correct_username = credentials.username == STORED_USERNAME
    password_hash = sha256(credentials.password.encode()).hexdigest()
    correct_password = password_hash == STORED_PASSWORD_HASH
    if not (correct_username and correct_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect user or password",
            headers={"WWW-Authenticate": "Basic"},
        )
    return credentials.username


@app.get("/users/me")
def read_user_me(current_username: str = Depends(get_current_username)):
    """获取当前用户的用户名。"""
    return {"username": current_username}

请求:

import requests
from requests.auth import HTTPBasicAuth

# 定义服务器地址
BASE_URL = "http://127.0.0.1:8000"


def test_get_user_me():
    # 正确的凭据
    correct_credentials = HTTPBasicAuth('john', 'secret')
    response = requests.get(f"{BASE_URL}/users/me", auth=correct_credentials)
    print("Response with correct credentials:")
    print(response.status_code, response.json())
    # 错误的凭据
    incorrect_credentials = HTTPBasicAuth('john', 'wrongpassword')
    response = requests.get(f"{BASE_URL}/users/me", auth=incorrect_credentials)
    print("Response with incorrect credentials:")
    print(response.status_code, response.text)


if __name__ == "__main__":
    test_get_user_me()

2、Bearer Token

Bearer token 身份验证是另一种常见的身份验证方法,通常与 OAuth 2.0 结合使用。FastAPI 提供了内置的支持来处理 bearer tokens。

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer

app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


# 假设我们有一个函数来验证 token 是否有效
def fake_decode_token(token):
    """模拟解码令牌的函数,检查令牌是否有效并返回用户信息"""
    if token == "validtoken":
        return {"username": "john", "scope": "admin"}
    else:
        return None


async def get_current_user(token: str = Depends(oauth2_scheme)):
    """获取当前用户,如果令牌无效则抛出未授权异常"""
    user = fake_decode_token(token)
    if user is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token",
            headers={"WWW-Authenticate": "Bearer"},
        )
    return user


@app.get("/users/me")
def read_user_me(current_user=Depends(get_current_user)):
    """读取当前用户的信息"""
    return current_user

请求:

import requests

# 定义服务器地址
BASE_URL = "http://127.0.0.1:8000"


def test_get_user_me():
    # 正确的令牌
    valid_token = "validtoken"
    headers = {"Authorization": f"Bearer {valid_token}"}
    response = requests.get(f"{BASE_URL}/users/me", headers=headers)
    print("Response with valid token:")
    print(response.status_code, response.json())
    # 错误的令牌
    invalid_token = "invalidtoken"
    headers = {"Authorization": f"Bearer {invalid_token}"}
    response = requests.get(f"{BASE_URL}/users/me", headers=headers)
    print("Response with invalid token:")
    print(response.status_code, response.text)


if __name__ == "__main__":
    test_get_user_me()

3、Session 管理

1)简单实现
from fastapi import FastAPI, Request, HTTPException, status
from fastapi.responses import JSONResponse
from itsdangerous import URLSafeTimedSerializer

import hashlib
import os


def hash_password(password: str) -> str:
    # 生成随机盐
    salt = os.urandom(16)
    # 创建新的哈希对象
    hasher = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, 100000)
    # 返回盐和哈希值的组合
    return salt.hex() + hasher.hex()


def verify_password(stored_password: str, provided_password: str) -> bool:
    # 从存储的密码中提取盐
    salt = bytes.fromhex(stored_password[:32])
    # 提取哈希值
    stored_hash = stored_password[32:]
    # 重新计算哈希值
    hasher = hashlib.pbkdf2_hmac('sha256', provided_password.encode('utf-8'), salt, 100000)
    # 比较哈希值
    return hasher.hex() == stored_hash


app = FastAPI()


serializer = URLSafeTimedSerializer("SECRET_KEY")
# 假设的用户数据库
fake_users_db = {
    "alice": {
        "username": "alice",
        "hashed_password": hash_password("secret_password")
    }
}


def authenticate_user(fake_db, username: str, password: str):
    user = fake_db.get(username)
    if not user or not verify_password(user["hashed_password"], password):
        return False
    return user


@app.post("/login")
async def login(request: Request):
    data = await request.json()
    username = data.get('username')
    password = data.get('password')
    user = authenticate_user(fake_users_db, username, password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    session_token = serializer.dumps(username)
    response = JSONResponse({"message": "Login successful"})
    response.set_cookie(key="session_token", value=session_token, httponly=True)
    return response


@app.get("/p
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值