用Twisted的Perspective Broker进行替代身份验证

39 阅读2分钟

在使用Twisted的Perspective Broker创建一个网络应用程序时,遇到一个问题:它自动使用MD5质询-响应方案进行身份验证。由于存在许多安全漏洞,最好不要在服务器端存储MD5哈希值。scrypt、bcrypt或pbkdf2等算法提供了更安全的替代方法。

尽管这些算法在Python中很容易获得,但目前还不清楚是否可以使用Perspective Broker实现自定义身份验证方案。从源代码来看,MD5似乎与系统紧密集成。

2. 解决方案

为了Perspective Broker实现自定义身份验证方案,只需要在一个根对象上实现一组方法调用,这些调用完成后即可访问所需的应用程序级对象。

无法重新使用PB内置的登录方法及其附带的线协议消息,但这没关系;这正是打算替换的东西。

注意,在构造一个PBServerFactory时,提供了一个根对象。如果想调用该对象上的方法,而不是执行“标准”的PB登录并在返回的化身(即,每个用户/每个连接对象)上调用方法,则需在PB客户端工厂上调用getRootObject,并在结果上使用callRemote。

以下是代码示例:

from twisted.cred import portal
from twisted.internet import protocol

class MyRealm:
    def requestAvatar(self, avatarId, mind):
        return MyAvatar(), None

class MyAvatar:
    def remote_doSomething(self, arg):
        # Do something with arg

class MyProtocol(protocol.Protocol):
    def connectionMade(self):
        self.factory.getRootObject().then(
            lambda root: root.callRemote('login', 'username', 'password')
        ).addCallbacks(
            self._onLoginSuccess,
            self._onLoginFailure
        )

    def _onLoginSuccess(self, result):
        # The login was successful; the result contains an avatar object
        avatar = result
        # Now we can call methods on the avatar, such as:
        avatar.callRemote('doSomething', 'Hello, world!')

    def _onLoginFailure(self, failure):
        # The login failed; handle the failure appropriately
        print(failure)

class MyFactory(protocol.Factory):
    def buildProtocol(self, addr):
        return MyProtocol()

portal = portal.Portal(MyRealm())

from twisted.internet import reactor

reactor.listenTCP(8000, MyFactory())
reactor.run()

在上面的示例中,MyRealm类充当身份验证领域,它定义了requestAvatar方法,该方法将返回一个MyAvatar对象和None。MyAvatar类是应用程序级别对象的表示,它定义了用作远程方法的remote_doSomething方法。

MyProtocol类是网络协议,它处理与客户端的连接。在connectionMade方法中,它首先获取根对象,然后调用login方法。login方法接受用户名和密码作为参数,如果成功,它将返回一个MyAvatar对象,否则返回一个错误。

如果登录成功,则调用_onLoginSuccess方法,其中调用doSomething方法在MyAvatar对象上执行远程操作。如果登录失败,则调用_onLoginFailure方法,其中处理错误。

最后,MyFactory类是一个协议工厂,它构建MyProtocol实例。然后,在reactor.listenTCP行中,将MyFactory实例绑定到端口8000,这将导致侦听传入连接并为每个连接构建MyProtocol实例。

reactor.run()行启动Twisted反应器,它将监听传入连接并调用适当的方法来处理它们。