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 開始監聽


發佈了19 篇原創文章 · 獲贊 5 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章