首先看下我的测试代码
from twisted.protocols.ftp import FTPFactory, FTPRealm from twisted.cred.portal import Portal from twisted.cred.checkers import AllowAnonymousAccess, FilePasswordDB from twisted.internet import reactor from twisted.internet import endpoints #pass.dat the same directory with ftp01.py # ===================== # jeff:bozo # grimmtooth:bozo2 # ===================== # p = Portal(FTPRealm(anonymousRoot='E:/', userHome='E:/'), [AllowAnonymousAccess(), FilePasswordDB("pass.dat")]) f = FTPFactory(p) endpoints.serverFromString(reactor,'tcp:21').listen(f) reactor.run()
Portal类是cred的认证类,是用户登陆认证入口,通过Portal来构造一个FTPFactory提供TCP的服务(FTP,FTP是建立在TCP基础上的)。
FTPRealm是从BaseFTPRealm派生,BaseFTPRealm实现了portal.IRealm的接口。
class BaseFTPRealm: """ Base class for simple FTP realms which provides an easy hook for specifying the home directory for each user. """ implements(portal.IRealm) def __init__(self, anonymousRoot): self.anonymousRoot = filepath.FilePath(anonymousRoot) def getHomeDirectory(self, avatarId): """ Return a L{FilePath} representing the home directory of the given avatar. Override this in a subclass. @param avatarId: A user identifier returned from a credentials checker. @type avatarId: C{str} @rtype: L{FilePath} """ raise NotImplementedError( "%r did not override getHomeDirectory" % (self.__class__,)) def requestAvatar(self, avatarId, mind, *interfaces): for iface in interfaces: if iface is IFTPShell: if avatarId is checkers.ANONYMOUS: avatar = FTPAnonymousShell(self.anonymousRoot) else: avatar = FTPShell(self.getHomeDirectory(avatarId)) return (IFTPShell, avatar, getattr(avatar, 'logout', lambda: None)) raise NotImplementedError( "Only IFTPShell interface is supported by this realm")
如果是匿名用户请求登陆则返回FTPAnonymousShell,否则返回FTPShell。这里FTPBaseRealm在用户登陆的时候直接以getHomeDirectory()作为FTP用户访问的根目录。
在看看FTPRealm,重写了getHomeDirectory,根据avatarId来返回一个子目录,这里特别要注意的是avatarId也就是FTP账号登陆的用户名。所以如果指定了userHome路径以后,还需要以用户名称来组织一个目录,这样才能让该用户正确访问到。
class FTPRealm(BaseFTPRealm): """ @type anonymousRoot: L{twisted.python.filepath.FilePath} @ivar anonymousRoot: Root of the filesystem to which anonymous users will be granted access. @type userHome: L{filepath.FilePath} @ivar userHome: Root of the filesystem containing user home directories. """ def __init__(self, anonymousRoot, userHome='/home'): BaseFTPRealm.__init__(self, anonymousRoot) self.userHome = filepath.FilePath(userHome) def getHomeDirectory(self, avatarId): """ Use C{avatarId} as a single path segment to construct a child of C{self.userHome} and return that child. """ return self.userHome.child(avatarId)
现在在反过来看看我例子里面的文件系统目录,匿名用户目录和用户目录都是E:盘,如果是匿名用户访问则直接访问E盘,否则如果是其他用户访问则访问的是E:\{用户名}目录。Portal的第二个参数指定了,用户的访问权限,可以匿名访问,而且可以通过文件密码的形式来访问,文件密码的格式(按照行),用户名:密码
[AllowAnonymousAccess(), FilePasswordDB("pass.dat")
这样通过几行代码就实现了一个简单的文件服务器了。也可以通过实现portal.IRealm接口来自定制访问权限。
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-15 22:41:58