Twisted用户验证之服务端详解

我也是不久前刚开始自学python的,前不久刚写了个小Demo,Demo中用到了Twisted这一块,所以就自己随手记录了一下在Demo中的心得,希望对python新手有一定的帮助,同时如果在以下有讲的不对的地方,也希望博友们能指出,小弟会感激不尽。

python中对客户端和服务端的通信提供了很好的支持,Twisted封装了大量有关python通信技术。而通信时对用户的验证也是很有必要的,这样可以保证服务端的安全。twisted提供cred模块, 将用户校验和业务逻辑分开以降低系统的耦合性。例如邮件服务中的pop3和imap可以使用同一套的验证逻辑和不同的业务逻辑。在Twisted中, pop3, imap, ssh、ftp和PB服务都使用了twisted.cred来进行验证。

其中,twisted.cred验证最重要的三个模块为:Portal、checkers和credentials,下面我用Demo中的代码来进行分析和讲解。


首先必须导入twisted.cred模块


from twisted.cred import portal,checkers,credentials


Main:下面是服务端Main里面运行的几行代码

p = portal.Portal(Realm())          # line 1
p.registerChecker(UserChecker())    # line 2
f =  pb.PBServerFactory(p)          # line 3
reactor.listenTCP(8206, f)          # line 4
reactor.run()                       # line 5

Main中line 1 实例化了一个Portal对象,Portal作为入口,每一次用户服务都和Portal进行交互,portal.Portal()带了一个参数,该参数其实是一个类,该类继承了portal.IRealm接口,portal.IRealm接口其实就是一个对象认证系统,每次用户验证完成之后,都将会通过该接口将服务端协议返回给客户端,供客户端调用,下面有代码可以供参考


class Realm:
	implements(portal.IRealm)      #   实现 portal中的IRealm接口   ,implements关键字由from zope.interface import implements导入
	
       def requestAvatar(self, user, mind, *interfaces):    #   重写IRealm接口内的requestAvator方法,该方法有4个参数,第二个参数是由
                                                            #   checkers.ICredentialsChecker接口的requestAvatarId方法返回用于识别用户唯一性的ID,后面会讲
                                                            #   到;第三个参数其实就是一个客户端对象,该客户端对象由客户端的pb.PbClientFactory的Login()方法
                                                            #   传入,该对象必须继承了pb.Referenceable或者是pb.Avator协议,一旦验证通过,服务端就可以通过该
                                                            #   对象协议与客户端通信,调用客户端方法;第四个参数是一个list, 用于决定返回的avatar类型, 通常
                                                            #   只有一个元素pb.IPerspective
		
                if pb.IPerspective not in interfaces:       #   检测pb.IPerspective是否在list中,如果不在当中,就抛出异常
			raise NotImplementedError

		def remove(): del userlist[user.account]
		user.client = mind       #  将每次验证通过后的客户端协议保存在user对象中,后面可以对任意处于连接状态的客户端进行调用
                return pb.IPerspective, Persective(mind), remove      #  该方法返回了一个三个元素的元祖,第一个元素为一个avator类型;第二个参数是一个协议对
                                                                      #  象,该对象必须继承自pb.Refrenceable或者是pb.Avator协议,该对象返回至客户端,客户端
                                                                      #  就可以通过该协议与服务端进行通信,调用服务器方法;第三个元素返回了一个回调函数,该
                                                                      #  函数在客户端与服务端断开连接的时候被触发

以下是第二个参数Perspective类代码:

#  该类远程调用客户端的方法
class ClientAvator(pb.Referenceable):    #  继承自 pb.Referenceable , 也可继承自 pb.Avator
	def __init__(self,client):
		self.client = client

	def callSelfRemote(self,clientFunName):          #  远程调用本次验证通过后的用户的客户端方法
		self.client.callRemote(clientFunName)

	def callUserRemote(self,clientFunName,user):     #  远程调用其它验证通过后的用户的客户端方法
		user.client.callRemote(clientFunName)

	def popupUserOnlineDlg(self,user=None):    
		if user:
			self.callUserRemote("popupUserOnlineDlg",user)
		else:
			self.callSelfRemote("popupUserOnlineDlg")

#   该类的方法供客户端远程调用
class Persective(ClientAvator):     #  继承了ClientAvator,ClientAvator继承自 pb.Referenceable
    def __init__(self,client):
        ClientAvator.__init__(self,client=client)

    def remote_NotifyOthserOnlineUsers(self):     #  注意远程调用的方法前缀,如果是继承pb.Refrenceable协议,对应的前缀就为remote_,如果继承的是pb.Avator协
                                                  #  议,前缀就是perspective_
        for u in userlist.itervalues():
            self.popupUserOnlineDlg(u)


Main中line 2就是向Portal里面注入一个用户登录时进行验证的凭据,也就是验证逻辑,UserChecker对象继承了checkers.ICredentialsChecker接口,该接口支持用户名/密码对、密钥等多种认证方式,其中的用户验证逻辑就可以通过重写接口内的 requestAvatarId方法实现,下面有代码可以供参考

class UserChecker:
	implements(checkers.ICredentialsChecker)       #  继承了 checkers.ICredentialsChecker 接口
	credentialInterfaces = (credentials.IUsernamePassword,credentials.IUsernameHashedPassword)    # 指明认证方式,这里指明的是用户名/密码对的认证方式
	
        def requestAvatarId(self,credentials):     ############### 重写 checkers.ICredentialsChecker接口的 requestAvatorId方法,该方法有2个参数,第二个参数
                                                                 # 是由客户端pb.PBClientFactory 的Login() 方法传过来的参数,关于Login()方法,后面会详细的
                                                                 # 为您讲解            
		
                accountPwd = credentials.username.split(',')
		if len(accountPwd)!=2:
			return defer.fail(u'非法的登录参数!')
		account,pwd = accountPwd
		if int(account) in userlist:
			return defer.fail(u"帐号已在别处登录")

		remarks,user = UserLogin(account,pwd)
		if user:
			userlist[user.account] = user
			return defer.succeed(user)         #  验证通过后,将user对象传递给IRealm的requestAvator方法处理
		else:
			return defer.fail(remarks)         #  验证失败,IRealm的requestAvator方法不执行,直接将错误信息返回至客户端


3、4、5三行代码,在我的之前的博文当中已经有了详细讲解,不是很清楚的可以去看下。


Main 中 line 3 实例化了一个服务工厂PbServerFactory,该工程实例化时接受了一个Portal实例化后的对象

Main 中 line 4 设置了监听的工厂及监听端口

Main 中 line 5 开始监听


你可能感兴趣的:(python,Twisted)