Python 如何在Twisted Klein服务器上禁用特定API端点的HTTP基本身份验证

Python 如何在Twisted Klein服务器上禁用特定API端点的HTTP基本身份验证,python,twisted,twistd,Python,Twisted,Twistd,我有一个简单的Twisted Klein服务器,全局启用了HTTP基本身份验证: from klein import Klein import attr from zope.interface import implementer from twisted.cred.portal import IRealm from twisted.internet.defer import succeed from twisted.cred.portal import Portal from twisted.

我有一个简单的
Twisted Klein
服务器,全局启用了HTTP基本身份验证:

from klein import Klein
import attr
from zope.interface import implementer
from twisted.cred.portal import IRealm
from twisted.internet.defer import succeed
from twisted.cred.portal import Portal
from twisted.cred.checkers import FilePasswordDB
from twisted.web.resource import IResource
from twisted.web.guard import HTTPAuthSessionWrapper, BasicCredentialFactory
from werkzeug.datastructures import MultiDict
from bson import json_util
import json


app = Klein()


# health check
@app.route('/health', methods=['GET'])
def health_check(request):
    return ''


# dataset query API
@app.route('/query/<path:expression>', methods=['GET'])
def query(request, expression):
    response = evaluate_expression(expression)
    return response


@implementer(IRealm)
@attr.s
class HTTPAuthRealm(object):
    resource = attr.ib()

    def requestAvatar(self, avatarId, mind, *interfaces):
        return succeed((IResource, self.resource, lambda: None))


def resource():
    realm = HTTPAuthRealm(resource=app.resource())
    portal = Portal(realm, [FilePasswordDB('./configs/server-auth.db')])
    credential_factory = BasicCredentialFactory('Authentication required')
    return HTTPAuthSessionWrapper(portal, [credential_factory])
从klein导入klein
导入属性
从zope.interface导入实现程序
从twisted.cred.portal导入IRealm
从twisted.internet.defer导入成功
从twisted.cred.portal导入门户
从twisted.cred.checker导入FilePasswordDB
从twisted.web.resource导入IResource
从twisted.web.guard导入HTTPAuthSessionWrapper,BasicCredentialFactory
从werkzeug.datastructures导入MultiDict
从bson导入json_util
导入json
app=Klein()
#健康检查
@app.route('/health',methods=['GET'])
def健康检查(请求):
返回“”
#数据集查询API
@app.route('/query/',methods=['GET'])
def查询(请求、表达式):
响应=计算表达式(表达式)
返回响应
@实施者(IRealm)
@属性
类HTTPAuthRealm(对象):
resource=attr.ib()
def requestAvatar(自我、化身、心智、*界面):
返回成功((IResource,self.resource,lambda:None))
def资源():
realm=HTTPAuthRealm(resource=app.resource())
portal=portal(领域,[FilePasswordDB('./configs/server auth.db'))
凭证工厂=基本凭证工厂(“需要身份验证”)
返回HTTPAuthSessionWrapper(门户,[凭证工厂])

我只想对特定的API端点禁用身份验证,例如,在本例中,对
/health
API端点禁用身份验证。我已经阅读了这些文档,但我无法完全理解它。

一种方法是只包装层次结构中需要验证的部分:

from twisted.web.resource import Resource

class Health(Resource):
    # ...

def resource():
    realm = HTTPAuthRealm(resource=app.resource())
    portal = Portal(realm, [FilePasswordDB('./configs/server-auth.db')])
    credential_factory = BasicCredentialFactory('Authentication required')
    guarded = HTTPAuthSessionWrapper(portal, [credential_factory])

    root = Resource()
    root.putChild(b"health", Health())
    root.putChild(b"this-stuff-requires-auth", guarded)

    return root
用于调度请求的正常资源遍历逻辑将从
根开始。如果请求是针对
/health
(或任何子级)的,那么它将转到
health
子级-这是在本例中创建的
health
实例。请注意,
HTTPAuthSessionWrapper
如何不涉及其中。如果请求是针对
/此内容需要auth
(或任何子项),则遍历确实会通过auth包装,因此需要进行身份验证

另一种方法是根据凭证改变你的化身。在这个方案中,您实际上仍然对每个人进行身份验证,但授权匿名用户访问某些层次结构

from twisted.cred.checkers import ANONYMOUS

@implementer(IRealm)
@attr.s
class HTTPAuthRealm(object):
    def requestAvatar(self, avatarId, mind, *interfaces):
        avatar = Resource()
        avatar.putChild(b"health", Health())
        if avatarId is not ANONYMOUS:
            avatar.putChild(b"this-stuff-requires-auth", SecretResource())
        return succeed((IResource, avatar, lambda: None))
您还需要为门户配置匿名凭据的凭据检查器:

from twisted.cred.checkers import AllowAnonymousAccess

portal = Portal(
    realm, [
        FilePasswordDB('./configs/server-auth.db'),
        AllowAnonymousAccess(),
    ],
)
在这种方法中,
HTTPAuthSessionWrapper
再次是您的根资源

匿名请求与
Anonymous
avatar标识符相关联,并且
HTTPAuthRealm
返回一个
IResource
,它只知道匿名用户可以使用的资源


具有有效用户凭据的请求与不同的化身标识符(通常是其用户名)关联,并且
HTTPAuthRealm
返回一个
IResource
,其中附加了更多子级,从而授予更多访问权限。

一种方法是仅包装层次结构中您希望进行身份验证的部分:

from twisted.web.resource import Resource

class Health(Resource):
    # ...

def resource():
    realm = HTTPAuthRealm(resource=app.resource())
    portal = Portal(realm, [FilePasswordDB('./configs/server-auth.db')])
    credential_factory = BasicCredentialFactory('Authentication required')
    guarded = HTTPAuthSessionWrapper(portal, [credential_factory])

    root = Resource()
    root.putChild(b"health", Health())
    root.putChild(b"this-stuff-requires-auth", guarded)

    return root
用于调度请求的正常资源遍历逻辑将从
根开始。如果请求是针对
/health
(或任何子级)的,那么它将转到
health
子级-这是在本例中创建的
health
实例。请注意,
HTTPAuthSessionWrapper
如何不涉及其中。如果请求是针对
/此内容需要auth
(或任何子项),则遍历确实会通过auth包装,因此需要进行身份验证

另一种方法是根据凭证改变你的化身。在这个方案中,您实际上仍然对每个人进行身份验证,但授权匿名用户访问某些层次结构

from twisted.cred.checkers import ANONYMOUS

@implementer(IRealm)
@attr.s
class HTTPAuthRealm(object):
    def requestAvatar(self, avatarId, mind, *interfaces):
        avatar = Resource()
        avatar.putChild(b"health", Health())
        if avatarId is not ANONYMOUS:
            avatar.putChild(b"this-stuff-requires-auth", SecretResource())
        return succeed((IResource, avatar, lambda: None))
您还需要为门户配置匿名凭据的凭据检查器:

from twisted.cred.checkers import AllowAnonymousAccess

portal = Portal(
    realm, [
        FilePasswordDB('./configs/server-auth.db'),
        AllowAnonymousAccess(),
    ],
)
在这种方法中,
HTTPAuthSessionWrapper
再次是您的根资源

匿名请求与
Anonymous
avatar标识符相关联,并且
HTTPAuthRealm
返回一个
IResource
,它只知道匿名用户可以使用的资源


具有有效用户凭据的请求与不同的化身标识符(通常是其用户名)关联,并且
HTTPAuthRealm
将返回一个
IResource
,其中附加了更多子项,从而授予更多访问权限。

谢谢!这管用!如果我不想为我的auth API设置预路径,我该怎么做?我尝试过类似这样的方法:
root.putChild(b'',受保护)
,但是当我尝试查询API时,
404没有这样的资源
错误。有一种方法可以满足您的需要。它涉及到定制
requestAvatar
的结果,而不是摆弄包括HTTPAuthSessionWrapper的资源层次结构。现在还没准备好写一个完整的例子,不过可能以后再写。好的,谢谢。如果你能给我举个例子,我将不胜感激。添加了一些东西,也许会有帮助。谢谢!这管用!如果我不想为我的auth API设置预路径,我该怎么做?我尝试过类似这样的方法:
root.putChild(b'',受保护)
,但是当我尝试查询API时,
404没有这样的资源
错误。有一种方法可以满足您的需要。它涉及到定制
requestAvatar
的结果,而不是摆弄包括HTTPAuthSessionWrapper的资源层次结构。现在还没准备好写一个完整的例子,不过可能以后再写。好的,谢谢。如果你能给我举个例子,我会很感激的。添加一些东西,也许会有帮助。