终于完成 APIFlask 对 MultiAuth 的支持了 🫡

终于完成apiflask对MultiAuth的支持了 :saluting_face:

改动比较大,欢迎大家Code Review和提建议。

主要的改动有以下几点:
①将API Keys认证从Token认证里分离出来了
新版本:

auth = APIKeyHeaderAuth()

旧版本:

auth = HTTPTokenAuth('apiKey', header='X-API-Key')

之前API Keys认证使用HTTPTokenAuth的原因是:它的底层实现实际上是flask-httpauth的HTTPTokenAuth
我查看了一下OpenAPI文档和其他资料,实际上API Keys可以位于查询参数(query parameters)、请求头或者cookie中。但是由于目前apiflask是使用的HTTPTokenAuth来实现API Keys认证,所以暂时只支持位于请求头中。
出于个人需求,apiflask后续可能会支持cookie认证。所以我先把它分离出来,为下一步的完整支持做准备。
旧用法仍然被兼容,但是会产生一个deprecation warning。

②把flask-httpauth的最低版本升级到了4.2.0
因为要支持MultiAuthoptional参数,所以flask-httpauth的最低版本被提升到了4.2.0。
在这个改动后,部分依赖版本不支持Python 3.8/3.9了…
如果不支持这个两个低版本,会对大家的使用造成影响,我建议这个功能等到3.0版本再发布

③security scheme的命名规则
修改当前的security scheme命名规则将会是破坏性的。所以我并没有实施,但是想在这里和大家讨论一下这个设计问题。
在当前版本中,如果security scheme的命名重复,apiflask会为其自动添加一个递增的后缀。
例如,当有两个认证类的security scheme被同时命名为"BasicAuth"时,在最终生成的OpenAPI文档中,第一个认证类的security schema名称是BasicAuth,第二个认证类的security scheme名称会被apiflask自动添加上一个后缀,被重命名为BasicAuth_2

auth = HTTPBasicAuth(security_scheme_name='BasicAuth')       # BasicAuth
auth2 = HTTPBasicAuth(security_scheme_name='BasicAuth')      # BasicAuth_2

我认为目前的命名规则并不好:

  • 擅自修改了用户输入:在用户不知情的情况下,修改了原本的security scheme名称
  • 违背了清晰原则:“BasicAuth_2”这样的命名并不好,只是简单地回避了命名冲突,没有提供其他有效信息
  • 增加了代码复杂性:代码实现需要检查命名是否冲突,并递推后缀(说实话,阅读和修改这段代码的时候有点痛苦… :joy:

目前我想到了两个方案:

  • 在命名冲突时,产生警告或异常
  • 后声明的命名覆盖掉先声明的命名

第二种方案参考自django-ninja
django-ninja的security schema名称是直接使用的认证类的类名。例如,下面这个示例(不良示例,请勿模仿)中两个认证类的名称都为“APIKey”,但是一个位于查询参数中,一个位于请求头中。根据Python规则,后定义的类会覆盖先定义的类。所以最后生成的OpenAPI文档中,API Key会位于请求头中。

class APIKey(AuthCheck, APIKeyQuery):
    pass


class APIKey(AuthCheck, APIKeyHeader):
    pass


@api.get("/multiple", auth=[APIKey(), APIKey()])
def multiple(request):
    return f"Token = {request.auth}"
4 个赞

security scheme 命名规则可以尝试重新设计。这个 feature 放到 3.0 好了,可以有 breaking change。

1 个赞

CookieAPIKeyAuthQueryAPIKeyAuth基本已经完成了
security scheme的命名规则我还没有想好该怎么处理,目前我更倾向于第二种,后声明的覆盖先声明的,并输出一个警告
或许应该开个Discussion讨论一下

1 个赞

覆盖+警告可以的

这个 PR 我晚点处理哦,想先把 Pydantic support 搞定

OK,security scheme命名规则的部分我还没有完成

3.0需要赶在PyCon China 2025前完成吗?
最近忙着面试,没什么时间

几个月前是这样规划的,现在已经放弃幻想了。

1 个赞

这个PR已经完成,可以合并了
抱歉,最近找工作耽误进度了(虽然暂时还是没有找到 :smiling_face_with_tear:

2 个赞

OK,两个 PR 我假期一起处理吧。

虽然有点站着说话不腰疼的感觉,不过或许可以趁着下一份工作开始之前多做点想做的事情 :nerd_face:

2 个赞