データベース認証付き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/
All Articles