JWT
约 672 字大约 2 分钟
我们编写了自定义的 JWT 授权中间件,使其可以在每次请求发起时,自动调用此中间件实现自动授权,并且,通过 Redis 和 Rust 库对用户信息进行缓存和解析,使其性能影响尽可能降到最低
async def jwt_authentication(token: str) -> GetUserInfoWithRelationDetail:
"""
JWT authentication
:param token:
:return:
"""
token_payload = jwt_decode(token)
user_id = token_payload.id
redis_token = await redis_client.get(f'{settings.TOKEN_REDIS_PREFIX}:{user_id}:{token_payload.session_uuid}')
if not redis_token or token != redis_token:
raise TokenError(msg='Token 已过期')
cache_user = await redis_client.get(f'{settings.JWT_USER_REDIS_PREFIX}:{user_id}')
if not cache_user:
async with async_db_session() as db:
current_user = await get_current_user(db, user_id)
user = GetUserInfoWithRelationDetail(**select_as_dict(current_user))
await redis_client.setex(
f'{settings.JWT_USER_REDIS_PREFIX}:{user_id}',
settings.JWT_USER_REDIS_EXPIRE_SECONDS,
user.model_dump_json(),
)
else:
# TODO: 在恰当的时机,应替换为使用 model_validate_json
# https://docs.pydantic.dev/latest/concepts/json/#partial-json-parsing
user = GetUserInfoWithRelationDetail.model_validate(from_json(cache_user, allow_partial=True))
return user
接口鉴权
在文件 backend/common/security/jwt.py
中,包含以下代码
# JWT authorizes dependency injection
DependsJwtAuth = Depends(HTTPBearer())
我们通过在接口函数中添加此依赖实现 JWT 快速校验,它可以帮助我们检查请求头中是否包含 Bearer Token,使用方式参考如下:
@router.get('/hello', summary='你好', dependencies=[DependsJwtAuth])
async def hello():
...
Token
内置 token 授权方式遵循 rfc6750,如果您想通过自定义请求头添加 token 进行授权,可以查看文章 Header Token
验证码登录
你可以通过此方式获取 token,在大多数情况下,这更适用于配合前端实现登录授权
我们在 fba 中使用 fast_captcha 生成 base64 验证码,然后通过接口进行数据返回;您可以通过在线 base64 转图片或配合前端项目将其转为图片进行预览,以下使其工作流程:
Swagger 登录
这是一种快捷的授权方式,仅用于调试目的,在服务启动后,进入 Swagger 文档,可通过此调试接口快速获取 token(无需验证码)
OAuth 2.0
这种授权方式通常适用于第三方平台认证登录,第三方授权成功后,将依据第三方平台信息自动创建本地用户并自动授权登录,这一切都是用户无感知的
但是,想要使用此方式进行授权,你需要先了解 OAuth 2.0 相关知识,并遵循第三方平台认证要求,获取平台应用相关密钥,最终,手动编码完成集成
我们在 fba 中使用 fastapi-oauth20 集成 OAuth 2.0,您可以在代码路径 backend/app/admin/api/v1/oauth2
中查看我们的官方实现示例