终于完成apiflask对MultiAuth
的支持了
改动比较大,欢迎大家Code Review和提建议。
主要的改动有以下几点:
①将API Keys认证从Token认证里分离出来了
新版本:
auth = HTTPAPIKeyAuth()
旧版本:
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
因为要支持MultiAuth
的optional
参数,所以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”这样的命名并不好,只是简单地回避了命名冲突,没有提供其他有效信息
- 增加了代码复杂性:代码实现需要检查命名是否冲突,并递推后缀(说实话,阅读和修改这段代码的时候有点痛苦…
)
目前我想到了两个方案:
- 在命名冲突时,产生警告或异常
- 后声明的命名覆盖掉先声明的命名
第二种方案参考自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}"