如何在Twisted-Klein服务器上禁用特定API端点的HTTP Basic Auth

时间:2017-02-14 14:44:41

标签: python twisted twistd

我有简单的Twisted-Klein服务器,全局启用了HTTP Basic Auth:

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])

我想仅为特定的API端点禁用auth,例如,在这种情况下,/health API端点。我已经阅读了这些文档,但我无法理解它。

1 个答案:

答案 0 :(得分:2)

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

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

用于调度请求的常规资源遍历逻辑将从root开始。如果请求适用于/health(或任何子级),则会转到root的{​​{1}}子级 - 这是此示例中创建的health实例。请注意Health如何参与其中。如果请求是HTTPAuthSessionWrapper(或任何子级),则遍历 通过auth包装,因此需要进行身份验证。

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

/this-stuff-requires-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(), ], ) 再次成为您的根资源。

匿名请求与{​​{1}}头像标识符相关联,而HTTPAuthSessionWrapper会返回ANONYMOUS,后者只知道匿名用户可以使用的资源。

使用有效用户凭据的请求与不同的头像标识符(通常是其用户名)相关联,HTTPAuthRealm会返回IResource并附加更多子级,从而授予更多访问权限。