關(guān)于pyftpdlib建立 FTP服務(wù)器的詳細(xì)內(nèi)容:
py-FTP服務(wù)器之一:虛擬運(yùn)行環(huán)境
py-FTP服務(wù)器之二:用戶(hù)配置文件
py-FTP服務(wù)器之三:?jiǎn)⒂肧SL連接
py-FTP服務(wù)器之四:ftp主程序
py-FTP服務(wù)器之五:其他
- 主程序是
ftp.py
ftp.py
同級(jí)要有一個(gè)rootftp
文件夾, 作為根目錄, ftp上傳來(lái)的文件全部丟里面
關(guān)于是否啟用SSL加密和多進(jìn)程的代碼
# 是否啟用ssl加密和多進(jìn)程模式
USE_SSL = False # 是否啟用ftps加密傳輸,通過(guò)修改單獨(dú)的文件設(shè)置,默認(rèn)是不用ssl
if 'ssl' in argv:
USE_SSL = True # 如果要啟用ssl,運(yùn)行時(shí)要加參數(shù) ssl
if 'mul' in argv:
USE_MULTIPLE_PROCESS = True # 開(kāi)啟多進(jìn)程模式, 運(yùn)行時(shí)要增加參數(shù) mul
注意: 在啟動(dòng)程序時(shí)需要在后面加參數(shù), 比如要啟用ssl, 則應(yīng)當(dāng)輸入python ftp.py ssl
, 如果還要開(kāi)啟多進(jìn)程, 則應(yīng)輸入python ftp.py ssl mul
MD5驗(yàn)證函數(shù)
這個(gè)函數(shù)是在官方給的基礎(chǔ)上做了一些簡(jiǎn)化.
# 驗(yàn)證用戶(hù)密碼hash后是否與原來(lái)的一樣,照著官方文檔寫(xiě)的,修改了一點(diǎn)
class DummyMD5Authorizer(DummyAuthorizer):
def validate_authentication(self, username, password, handler):
hash = md5(password.encode('utf-8')).hexdigest() # 與md5USerPassword.py上的算法一致
try:
if self.user_table[username]['pwd'] != hash:
raise KeyError
except KeyError:
raise AuthenticationFailed
從文本文件加載用戶(hù)信息
# 讀取用戶(hù)權(quán)限文件,向虛擬用戶(hù)管理器添加用戶(hù)
def add_user(authorizer):
# 用戶(hù)權(quán)限文件
userfile = 'userMD5.txt' # 文件格式如下(md5加密后的文件,運(yùn)行md5UserPassword.py后自動(dòng)生成)
'''
# 備注文字(用tab間隔開(kāi)來(lái))
username md5(password) path perm
username md5(password) path perm
username md5(password) path perm
'''
# 用戶(hù)列表
user_list = []
split_str = '\t'
# 從userMD5.txt讀取用戶(hù)信息
with open(userfile) as f:
for line in f:
line = line.replace('\n', '') # 去掉最后的\n
if not line.startswith('#') and line: # #后面是備注
if len(line.split(split_str)) == 4: # 用戶(hù)名/密碼/路徑/權(quán)限
user_list.append(line.split(split_str))
else:
print("userMD5.txt配置錯(cuò)誤: %s" % line)
# 添加用戶(hù)
for user in user_list:
authorizer.add_user(user[0], user[1], './rootftp' + user[2], perm=user[3], msg_login="歡迎光臨", msg_quit="歡迎下次光臨")
print('[%s\t---\t%s\t%s]' % (user[0], user[3], user[2]))
# 返回虛擬用戶(hù)管理器
return authorizer
被動(dòng)模式PASV
- 如果有電腦在局域網(wǎng)中要連接外網(wǎng)的FTP, 則建議使用被動(dòng)模式PASV進(jìn)行連接
- 設(shè)置一個(gè)假的IP地址, 確定一個(gè)被動(dòng)模式端口的范圍(默認(rèn)設(shè)置為這個(gè), 服務(wù)器的最后5000多個(gè)端口號(hào))
# 被動(dòng)模式配置
# Specify a masquerade address and the range of ports to use for
# passive connections. Decomment in case you're behind a NAT.
# 設(shè)置假I(mǎi)P地址發(fā)回給ftp客戶(hù)端,設(shè)置被動(dòng)模式的端口區(qū)間(最大65535)
handler.masquerade_address = '151.25.42.11' # ftp服務(wù)器的偽IP地址
handler.passive_ports = range(60000, 65535) # 被動(dòng)模式下的隨機(jī)端口
完整代碼ftp.py
# coding:utf-8
from pyftpdlib.servers import FTPServer, MultiprocessFTPServer
from pyftpdlib.authorizers import DummyAuthorizer, AuthenticationFailed
from hashlib import md5
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.handlers import TLS_FTPHandler # TLS_FTPHandler需要pip安裝pyopenssl
from sys import argv # 用來(lái)讀取啟動(dòng)py文件時(shí)的命令行參數(shù)
# 是否啟用ssl加密
USE_SSL = False # 是否啟用ftps加密傳輸,通過(guò)修改單獨(dú)的文件設(shè)置,默認(rèn)是不用ssl
if 'ssl' in argv:
USE_SSL = True # 如果要啟用ssl,運(yùn)行時(shí)要加參數(shù) ssl
if 'mul' in argv:
USE_MULTIPLE_PROCESS = True # 開(kāi)啟多進(jìn)程模式
# 驗(yàn)證用戶(hù)密碼hash后是否與原來(lái)的一樣,照著官方文檔寫(xiě)的,修改了一點(diǎn)
class DummyMD5Authorizer(DummyAuthorizer):
def validate_authentication(self, username, password, handler):
hash = md5(password.encode('utf-8')).hexdigest() # 與md5USerPassword.py上的算法一致
try:
if self.user_table[username]['pwd'] != hash:
raise KeyError
except KeyError:
raise AuthenticationFailed
# 讀取用戶(hù)權(quán)限文件,向虛擬用戶(hù)管理器添加用戶(hù)
def add_user(authorizer):
# 用戶(hù)權(quán)限文件
userfile = 'userMD5.txt' # 文件格式如下(md5加密后的文件,運(yùn)行md5UserPassword.py后自動(dòng)生成)
'''
# 備注文字(用tab間隔開(kāi)來(lái))
username md5(password) path perm
username md5(password) path perm
username md5(password) path perm
'''
# 用戶(hù)列表
user_list = []
split_str = '\t'
# 從userMD5.txt讀取用戶(hù)信息
with open(userfile) as f:
for line in f:
line = line.replace('\n', '') # 去掉最后的\n
if not line.startswith('#') and line: # #后面是備注
if len(line.split(split_str)) == 4: # 用戶(hù)名/密碼/路徑/權(quán)限
user_list.append(line.split(split_str))
else:
print("userMD5.txt配置錯(cuò)誤: %s" % line)
# 添加用戶(hù)
for user in user_list:
authorizer.add_user(user[0], user[1], './rootftp' + user[2], perm=user[3], msg_login="歡迎光臨", msg_quit="歡迎下次光臨")
print('[%s\t---\t%s\t%s]' % (user[0], user[3], user[2]))
# 返回虛擬用戶(hù)管理器
return authorizer
#
def main():
# 用戶(hù)驗(yàn)證
# Instantiate a dummy authorizer for managing 'virtual' users 創(chuàng)建虛擬用戶(hù)管理器
# authorizer = DummyAuthorizer()
authorizer = DummyMD5Authorizer() # 因?yàn)橐?yàn)證hash值,所以改成這個(gè)了類(lèi)了,官方寫(xiě)的, 這個(gè)類(lèi)繼承自DummyAuthorizer類(lèi)
# Define a new user having full r/w permissions and a read-only anonymous user
# 讀取userMD5.txt文件,綁定 用戶(hù)-權(quán)限
authorizer = add_user(authorizer) # 寫(xiě)成了一個(gè)函數(shù)add_user()來(lái)自動(dòng)讀取userMD5.txt
# authorizer.add_anonymous(os.getcwd()) # 匿名用戶(hù),關(guān)閉
# ftp主控制器
# Instantiate FTP handler class
# 綁定FTP控制器
if not USE_SSL:
handler = FTPHandler # ftp傳輸
if USE_SSL:
handler = TLS_FTPHandler # ftps傳輸 = ftp + ssl
handler.authorizer = authorizer # 綁定用戶(hù)管理器
# ssl加密
if USE_SSL:
handler.certfile = 'crt_key.pem' # 此處需要插入自簽名證書(shū)文件base64編碼的pem
# requires SSL for both control and data channel
# 啟用ssl加密傳輸
# handler.tls_control_required = True # 控制連接啟用ssl加密
handler.tls_data_required = True # 數(shù)據(jù)連接啟用ssl加密
# 錦上添花
# Define a customized banner (string returned when client connects)
# 定義ftp客戶(hù)端[連接成功歡迎詞]
handler.banner = "歡迎你我尊貴的客人蒞臨指導(dǎo)"
# 被動(dòng)模式配置
# Specify a masquerade address and the range of ports to use for
# passive connections. Decomment in case you're behind a NAT.
# 設(shè)置假I(mǎi)P地址發(fā)回給ftp客戶(hù)端,設(shè)置被動(dòng)模式的端口區(qū)間(最大65535)
handler.masquerade_address = '151.25.42.11' # ftp服務(wù)器的偽IP地址
handler.passive_ports = range(60000, 65535) # 被動(dòng)模式下的隨機(jī)端口
# ip限制及端口設(shè)定
# Instantiate FTP server class and listen on 0.0.0.0:8081
# 設(shè)置不限制IP地址訪問(wèn),端口8081,使用TCP端口8081
address = ('0.0.0.0', 8081) # ip限制及連接端口(需要在安全組里放通這個(gè)端口)
# 多進(jìn)程模式是否開(kāi)啟
if USE_MULTIPLE_PROCESS:
server = MultiprocessFTPServer(address, handler)
else:
server = FTPServer(address, handler)
# 最大連接數(shù)限制
# set a limit for connections
# 設(shè)置最大連接數(shù),和相同IP地址的最大同時(shí)連接數(shù)
server.max_cons = 50
server.max_cons_per_ip = 20
# 萬(wàn)事俱備,只欠東風(fēng)
# start ftp server
# 啟動(dòng)ftp服務(wù)器
server.serve_forever()
# 啟動(dòng)
if __name__ == '__main__':
main()
啟動(dòng)
啟動(dòng)命令: python ftp.py ssl mul
后臺(tái)運(yùn)行: nohup python ftp.py >> log 2>&1 &