利用FastAPI内置的HTTPBearer工具来验证bearer令牌的有效性,并在Python API应用程序中获取有效的用户会话
需要对你的Python API调用进行验证但找不到相关教程或SDK吗?这几个简单的步骤就能搞定!
使用Clerk和FastAPI进行认证和Bearer令牌验证
在构建SaaS时,我发现Clerk目前还没有提供Python SDK(可能还没有?),所以我决定深入研究一下看看有没有办法使用FastAPI内置的安全工具(FastAPI安全工具)来读取和验证从我的前端应用发送的承载令牌认证信息。
快速开始,只需按照以下步骤。
A. 准备工作如下如果你已经有一个 FastAPI 应用程序,可以直接跳过这些内容。
1. 安装依赖项.使用pip
将这些包添加到你的Python项目中:
# 创建虚拟环境
python -m venv venv
# 激活虚拟环境(venv)
source venv/bin/activate
# 安装依赖
pip install fastapi uvicorn
2. 查看 HTTP 请求的内容
在 server.py
文件中创建一个监听 8000 端口的服务器,比如:
从 fastapi 导入 FastAPI 作为 app
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
如果 __name__ == "__main__":
导入 uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
我喜欢用这种方法来运行 uvicorn
,这样就不需要单独安装 uvicorn
的命令行工具,而是直接运行 python server.py
即可。试试看:可以尝试在命令行中输入 python server.py
来启动服务器。
python server.py
启动服务器进程 [54863] 成功。
等待应用启动。
应用启动完成。
Uvicorn 正在 http://0.0.0.0:8000 上运行中(按 CTRL+C 可停止程序)。
验证Bearer Token
1. 解析携带令牌。
我们将使用FastAPI HTTPBearer实用程序从Authorization
HTTP头读取令牌。
当然我们也可以直接通过字符串操作从头部解析出这个token,不过使用这个工具能让代码更易读。代码整洁就更好了。
在 server.py
文件中加入以下代码行(如下注释 1 至 6)。
from fastapi import FastAPI, Depends # <- (1) # 导入相关模块
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer # <- (2) # 导入相关模块
from typing import Annotated # <- (3)
app = FastAPI()
security = HTTPBearer() # <- (4) security = HTTPBearer()
@app.get("/")
async def root(
credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)] # <- (5) 凭证: Annotated[HTTPAuthorizationCredentials, Depends(security)]
):
print(f"收到的token: {credentials.credentials[:10]}...") # <- (6)
return {"message": "Hello World"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
让我们启动服务器,然后做一些测试。
python server.py
INFO: 服务器进程 [55315] 已启动运行
INFO: 正在等待应用启动。
INFO: 应用启动完成。
INFO: Uvicorn 正在 http://0.0.0.0:8000 上运行中(按 Ctrl+C 即可停止)
从另一个终端输入。
# 发送一个没有认证令牌的请求
curl -i localhost:8000
HTTP/1.1 403 Forbidden
日期: 2024年2月17日 09:51:19 GMT
服务器: uvicorn
内容大小: 30
内容类型: application/json
{"detail":"未认证"}
# 现在我发送一个(随便的)认证令牌
curl -i localhost:8000 -H 'Authorization: Bearer 超级秘密'
HTTP/1.1 200 OK
日期: 2024年2月17日 09:52:41 GMT
服务器: uvicorn
内容大小: 25
内容类型: application/json
{"message":"Hello World"}
# ... 并且我可以看到我的服务器打印以下内容:
获取令牌: supersecre...
INFO: 127.0.0.1:50722 - "GET / HTTP/1.1" 200 OK
2. 验证 token.
使用离线验证,我们可以使用我们的JWT签名密钥来验证令牌的有效性,其中“JWT”代表“JSON Web Token”。
安装如下所示包含 cryptography
包的 PyJWT 库。
pip install "pyjwt[crypto]" # 安装 pyjwt 包及其 crypto 扩展
在 server.py
文件中,添加或修改以下几行。
import requests # <- (1)
from fastapi import FastAPI, Depends, Response, status # <- (2)
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from typing import Annotated
CLERK_PEM_PUBLIC_KEY = """
-----BEGIN PUBLIC KEY-----
<YOUR JWT PUBLIC KEY>
-----END PUBLIC KEY-----
""" # <- (3)
app = FastAPI()
security = HTTPBearer()
@app.get("/")
async def root(
credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)],
response: Response # <- (4)
):
print(f"收到的令牌是: {credentials.credentials[:10]}...")
# (5) 添加以下部分
try:
jwt.decode(token, key=CLERK_PEM_PUBLIC_KEY, algorithms=['RS256'])
return {"message": "Hello World"}
except jwt.exceptions.PyJWTError:
response.status_code = status.HTTP_400_BAD_REQUEST
return {"message": "无效的令牌"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
要测试这一点,我们可以在控制台中运行以下代码:await Clerk.session.getToken()
,从而找到前端应用在登录时使用的 token。
从终端运行以下:
# 没有有效的token
curl -i localhost:8000 -H 'Authorization: Bearer invalidtoken'
HTTP/1.1 400 Bad Request
date: Sun, 18 Feb 2024 13:21:01 GMT
server: uvicorn
content-length: 27
content-type: application/json
{"message":"无效的Token"}
# 有有效的token
curl -i localhost:8000 -H 'Authorization: Bearer eyJhbGc...'
HTTP/1.1 200 OK
date: Sun, 18 Feb 2024 13:08:58 GMT
server: uvicorn
content-length: 25
content-type: application/json
{"message":"Hello World"}
而且它有效了🎉!应用程序确实检查token是否有效且尚未过期。
这些资源想联系我吗?我还在以下社交平台上也很活跃: