データベース認証付きFTPサーバー

画像

サーバーに展開するための既製のFTPサーバーが多数あります。 しかし、FTPがサーバー上ですでに実行されているため、代替ポートでFTPサーバーを上げる必要がありました。 また、ユーザーがファイルのあるフォルダにのみアクセスできるようにします。 Pythonツールを使用して何ができるかを尋ねることにしました。 検索はすぐにpyFTPdライブラリを返しました。


このライブラリの既製の例は、FTPサーバーを数分で上げる方法を示しています。 ユーザーとユーザーがアクセスできるファイルへのパスは、データベースに保存されます。 したがって、このライブラリーを基礎としてデータベースにリンクすることが決定されました。 そして、あなた自身のグッズを備えたFTPサーバーを入手してください:)

データベース


データベース内のテーブルは、複雑なものを超えるものを表しません。
SQL:
CREATE TABLE ` users ` (
` id ` int ( 11 ) NOT NULL auto_increment,
` username ` varchar ( 255 ) NOT NULL ,
` password ` varchar ( 32 ) NOT NULL ,
` path ` varchar ( 255 ) NOT NULL ,
` perm ` varchar ( 8 ) default NULL ,
PRIMARY KEY ( ` id ` ),
KEY ` username ` ( ` username ` )
)


使用される主なパラメーターは、ログイン、パスワード、アクセス権、ユーザーがアクセスできるフォルダーへのパスです。

実装


すぐに行われた最初のことは、データベースを操作するための小さなクラスラッパーでした。 したがって、ニーズに合わせて書き直して、MySQLを任意のデータベースに置き換えることができます。

class DB :

init = None
db = None
def __init__ ( self ,init_db):
""" Constructor """
self . init = init_db
self . db = self . init()

def doSql ( self ,sql):
""" Handle SQL """
try :
self . db . execute(sql)
except :
try :
self . db = self . init()
self . db . execute(sql)
except :
print "error:" + sql

def getDB ( self ):
""" """
return self . db

def getLastId ( self ):
"""Get last insert ID"""
sql = "select LAST_INSERT_ID() as `id`"
self . doSql(sql)
data = self . db . fetchone()
if 'id' in data:
return data[ 'id' ]
else :
return None


ウィキペディアとサーバー自体のソースコードを検討した結果、承認とファイルの場所の選択を担当するメソッドが特定されました。 その後、これらの方法を再定義する必要があり、問題は解決しました。
サーバーの起動方法は次のとおりです。
. . .
def starterver ( self ):
"""Run server"""
authorizer = self . ftpserver . DummyAuthorizer()

authorizer . validate_authentication = self . my_validate_authentication
authorizer . get_home_dir = self . my_get_home_dir
authorizer . get_perms = self . my_get_perms
authorizer . get_msg_login = self . my_get_msg_login
authorizer . get_msg_quit = self . my_get_msg_quit

authorizer . has_perm = self . my_has_perms
authorizer . has_user = self . my_has_user

# Instantiate FTP handler class
ftp_handler = ftpserver . FTPHandler
ftp_handler . authorizer = authorizer
ftp_handler . passive_ports = range ( 63000 , 63500 )
# Define a customized banner (string returned when client connects)
ftp_handler . banner = "pyftpdlib %s based ftpd ready." % ftpserver . __ver__

address = ( '127.0.0.1' , 23 )
ftpd = ftpserver . FTPServer(address, ftp_handler)

# set a limit for connections
ftpd . max_cons = 256
ftpd . max_cons_per_ip = 5

# start ftp server
ftpd . serve_forever()
. . .


オーバーライドされた主なメソッド



validate_authentication-ユーザー認証を担当します。
get_home_dir-ユーザーがアクセスできるホームディレクトリを取得します。
get_perms-データアクセス許可を取得します。
has_perm-ディレクトリへのユーザーアクセス権の確認
has_user-ユーザーの存在を確認します

ユーザーと連携するために、別のクラスが実装されました。
from db import DB
from config import init_db
class User :

def __init__ ( self ):
"""Init"""

def auth ( self ,username,password):
"""Make auth"""
sql = "select * from `users` where `username`=' %s ' and `password`=' %s '" % (username,password)
db = DB(init_db)
db . doSql(sql)
res = db . getDB() . fetchone()
if res:
return 1
else :
return None

def getPath ( self ,username):
"""Return path by username"""
sql = "select `path` from `users` where `username`=' %s '" % username
db = DB(init_db)
db . doSql(sql)
uparam = db . getDB() . fetchone()
if uparam:
return uparam[ 'path' ]
else :
return None

def getPerm ( self ,username):
"""Return permission by username"""
sql = "select `perm` from `users` where `username`=' %s '" % username
db = DB(init_db)
db . doSql(sql)
uparam = db . getDB() . fetchone()
if uparam:
return uparam[ 'perm' ]
else :
return ''

def hasUser ( self ,username):
"""Checj user into DB"""
sql = "select `id` from `users` where `username`=' %s '" % (username)
db = DB(init_db)
db . doSql(sql)
uparam = db . getDB() . fetchone()
if uparam:
return 1
else :
return 0


必要なメソッドをラップします。
def my_validate_authentication ( self ,username,password):
return User() . auth(username, password)

def my_get_home_dir ( self ,username):
return User() . getPath(username)

def my_get_perms ( self ,username):
return User() . getPerm(username)

def my_get_msg_login ( self ,username):
return 'hello msg login'

def my_get_msg_quit ( self ,username):
return 'byu msg quit'

def my_has_user ( self ,username):
return User() . hasUser(username)

def my_has_perms ( self ,username, perm, path = None ):
return 1


結果


ユーザーはデータベースを介してログインし、自分のディレクトリにアクセスします。

改善できるもの


キャッシュを使用して、データベース呼び出しをオフロードできます。 たとえば、memcache。 ここには非常に多くのオプションがあります:


ソースコード


ソースコードはこちらからダウンロードできます

ソース


http://en.wikipedia.org/wiki/File_Transfer_Protocol
http://code.google.com/p/pyftpdlib/

Source: https://habr.com/ru/post/J108796/


All Articles