はじめに
認証は、ログイン要求中にユーザーの身元を確認するプロセスです。認証プロセスでは、ユーザーはユーザー名とパスワードの形式で資格情報を提出します。その後、アプリケーションはそれらのログイン資格情報を保存されたデータベースエントリと照合します。一致がある場合、アプリケーションはユーザーにシステムへのアクセスを許可します。
キャッシュメカニズムのないMySQLやPostgreSQLのようなリレーショナルデータベースにログイン資格情報を保存することは、まだ一般的で実用的な手法ですが、以下の制限があります:
-
データベースの過負荷。ユーザーがログイン要求を提出するたびに、アプリケーションはデータベースサーバーへの往復を行い、データベーステーブルからユーザーの資格情報を確認する必要があります。データベースは他の読み書き要求も処理する可能性があるため、このプロセス全体でデータベースに過負荷がかかり、遅くなります。
-
従来のディスクベースのデータベースはスケーラビリティの問題を抱えています。アプリケーションが1秒あたり数千のリクエストを受け取る場合、ディスクベースのデータベースでは最適なパフォーマンスが得られません。
上記の課題を克服するために、Redisを使用してユーザーのログイン資格情報をキャッシュすることができます。これにより、ログインリクエストごとにバックエンドデータベースに接続する必要がありません。Redisは、コンピュータのRAMを使用してデータをキーと値のペアで格納する、最も人気のある超高速データストアの1つです。このガイドでは、Ubuntu 22.04サーバー上のPython/MySQLアプリケーションでセッション処理の高速化にRedisデータベースを使用します。
前提条件
このチュートリアルを開始する前に、以下の設定が必要です:
-
非ルートの
sudo
ユーザーを作成します。 -
新しい
sudo
ユーザーアカウントに切り替えて、以下をインストールしてください:
ステップ1 — RedisとMySQLのPythonデータベースドライバのインストール
このアプリケーションは、ユーザーの名前やパスワードなどの認証情報をMySQLデータベースサーバーに永続的に保存します。ユーザーがアプリケーションにログインすると、PythonスクリプトがMySQLデータベースをクエリし、詳細を保存された値と照合します。その後、Pythonスクリプトはユーザーのログイン情報をRedisデータベースにキャッシュし、他の将来のリクエストに対応します。このロジックを完了するために、PythonスクリプトにはMySQLとRedisサーバーとの通信に必要なデータベースドライバ(Pythonモジュール)が必要です。以下の手順に従ってドライバをインストールしてください:
- パッケージ情報インデックスを更新し、以下のコマンドを実行してPythonパッケージマネージャーである
python3-pip
をインストールします。これにより、Python標準ライブラリに含まれていない追加のモジュールをインストールできるようになります。
- PythonのMySQLドライバをインストールします:
- PythonのRedisドライバをインストールします:
MySQLとRedisとの通信に必要なドライバをインストールした後、次のステップに進み、MySQLデータベースを初期化します。
ステップ2 — サンプルMySQLデータベースの設定
このガイドでは、1つのMySQLテーブルが必要です。本番環境では、他のリクエストに対応するために数十のテーブルを持つことができます。次のコマンドを実行してデータベースを設定し、テーブルを作成してください:
-
MySQLデータベースサーバーに
root
ユーザーとしてログインします: -
パスワードが求められたら、MySQLサーバーの
root
パスワードを入力し、ENTER
キーを押して進みます。その後、次のコマンドを実行して、サンプルのcompany
データベースとcompany_user
アカウントを作成します。強力なパスワードであるexample-mysql-password
を入力してください:
-
以下の出力が表示されることを確認して、前のコマンドが正常に実行されたことを確認してください:
-
新しい
company
データベースに切り替えます: -
次の出力を確認して、新しいデータベースに接続されていることを確認します:
-
system_users
テーブルを作成します。user_id
列は、各ユーザーを一意に識別するためのPRIMARY KEY
として機能します。username
およびpassword
列は、ユーザーがアプリケーションにログインするために提出するログイン資格情報です。first_name
およびlast_name
列には、ユーザーの名前が格納されます: -
次の出力を確認して、新しいテーブルが作成されていることを確認してください:
-
サンプルデータで
system_users
テーブルを埋める。セキュリティのためにMySQLの組み込み関数MD5(...)
を使用してパスワードをハッシュ化する。 -
以下は出力の確認です。
-
system_users
テーブルをクエリしてデータが入っていることを確認します。 -
以下の出力を確認してください:
-
MySQLデータベースからログアウトする:
これでアプリケーションに適切なMySQLデータベースが設定されました。次のステップでは、サンプルデータベースと通信するPythonモジュールを作成します。
ステップ3 — Python用の中央MySQLゲートウェイモジュールを作成する
Pythonプロジェクトをコーディングする際には、各タスクごとに別のモジュールを作成してコードの再利用性を高めるべきです。このステップでは、PythonスクリプトからMySQLデータベースに接続してクエリを実行するための中央モジュールを設定します。以下の手順に従ってください:
-
project
ディレクトリを作成します。このディレクトリはPythonソースコードファイルを他のシステムファイルから分離します: -
新しい
project
ディレクトリに切り替えます。 -
nano
テキストエディタを使用して、新しいmysql_db.py
ファイルを開きます。このファイルはMySQLデータベースと通信するPythonモジュールをホストします。 -
以下の情報を
mysql_db.py
ファイルに入力してください。company_user
アカウントの正しいMySQLパスワードでexample-mysql-password
を置き換えてください:~/project/mysql_db.py -
mysql_db.py
ファイルを保存して閉じます。
mysql_db.py
モジュールファイルには、次の2つのメソッドを持つ1つのクラス(MysqlDb:
)があります:
– db_con(self):
:以前に作成したサンプルのcompany
データベースに接続し、return mysql_con
ステートメントを使用して再利用可能なMySQL接続を返します。
– query(self, username, password):
:ユーザー名とパスワードを受け取り、system_users
テーブルをクエリして一致するかどうかを調べます。条件付きのif row_count < 1: ... else: return result[1]
ステートメントは、ユーザーがテーブルに存在しない場合はブール値False
を返し、アプリケーションが一致を見つけた場合はユーザーのパスワード(result[1]
)を返します。
MySQLモジュールが準備できたら、次のステップに進んでRedisキーバリューストアに通信する類似のRedisモジュールをセットアップします。
ステップ4 – Pythonの中央Redisモジュールの作成
このステップでは、Redisサーバーに接続するモジュールを作成します。次の手順を実行してください。
-
新しい
redis_db.py
ファイルを開きます: -
redis_db.py
ファイルに以下の情報を入力してください。Redisサーバーの正しいパスワードであるexample-redis-password
を置き換えてください:~/project/redis_db.py -
redis_db.py
ファイルを保存して閉じます。
-
上記のファイルには、1つのクラス(
RedisDb:
)があります。 -
このクラスの下には、
db_con(self):
メソッドがあり、提供された認証情報を使用してRedisサーバーに接続し、return redis_con
ステートメントを使用して再利用可能な接続を返します。
Redisクラスを設定した後、次のステップでプロジェクトのメインファイルを作成します。
ステップ5 — アプリケーションのエントリーポイントの作成
すべてのPythonアプリケーションには、エントリーポイントまたはアプリケーションの実行時に実行されるメインファイルが必要です。このファイルでは、認証されたユーザーの現在のサーバーの時刻を表示するコードを作成します。このファイルでは、作成したカスタムのMySQLおよびRedisモジュールを使用してユーザーを認証します。以下の手順に従って、ファイルを作成してください。
-
新しい
index.py
ファイルを開きます: -
index.py
ファイルに以下の情報を入力してください:~/project/index.py -
index.py
ファイルを保存して閉じます。
-
index.py
ファイルでは、import...
セクションに以下のモジュールがプロジェクトに追加されます。-
utf_8
、base64
、md5
、およびjson
、テキストエンコーディングおよびフォーマットモジュール。 -
http.server
、HTTPStatus
、およびsocketserver
、Webサーバーモジュール。 -
datetime
、時刻/日付モジュール。 -
mysql_db
およびredis_db
、以前に作成したMySQLおよびRedisサーバーへのアクセスのためのカスタムモジュール。
-
-
HttpHandler(http.server.SimpleHTTPRequestHandler)
は、HTTPサーバーのためのハンドラークラスです。クラス内では、do_GET(self)
メソッドがHTTPGETリクエストを処理し、認証済みユーザーに対してシステムの日時を表示します。 -
if ... : else: ...
のロジックでは、Pythonスクリプトは論理的なif redis_client.exists(auth_user):
文を実行して、Redisサーバーにユーザーの資格情報が存在するかどうかを確認します。ユーザーの詳細が存在し、Redisに保存されているパスワードがユーザーが送信したパスワードと一致しない場合、アプリケーションは{"error": "Invalid username/password."}
エラーを返します。
ユーザーの詳細がRedisサーバーに存在しない場合、アプリケーションはmysql_resp = mysql_server.query(auth_user, auth_password)
ステートメントを使用してMySQLデータベースサーバーにクエリを送信します。ユーザーが提供したパスワードがデータベースに保存されている値と一致しない場合、アプリケーションは{"error": "Invalid username/password."}
エラーを返します。それ以外の場合、アプリケーションはredis_client.set(auth_user, mysql_resp)
ステートメントを使用してユーザーの詳細をRedisサーバーにキャッシュします。
-
ユーザーの資格情報がRedis/MySQLの詳細と一致する場合、アプリケーションは
{"time": current_time, ...}
ステートメントを使用してシステムの現在の日付/時刻を表示します。出力のauthorized by
エントリでは、アプリケーションでユーザーを認証するデータベースサーバーが表示されます。
これでアプリケーションのメインファイルの設定が完了しました。次のステップでは、アプリケーションをテストします。
ステップ6 – アプリケーションのテスト
このステップでは、Redisのキャッシュメカニズムが機能するかどうかを確認するためにアプリケーションを実行します。以下のコマンドを実行してアプリケーションをテストしてください。
-
以下の
python3
コマンドを使用してアプリケーションを実行します: -
アプリケーションのカスタムWebサーバーが実行されていることを確認してください:
-
新しいターミナルウィンドウでサーバへの別の
SSH
接続を確立し、以下のcurl
コマンドを実行して、john_doe
の認証情報を使用して4つのGETリクエストを送信してください。4つのリクエストを単一のコマンドで送信するために、http://localhost:8080/
のURLの末尾に[1-4]
を追加します: -
以下の出力を確認してください。MySQLサーバーは最初の認証リクエストのみ処理します。その後、Redisデータベースが次の3つのリクエストを処理します。
アプリケーションのロジックは予想通りに動作しています。
結論
このガイドでは、Redisサーバーを使用して、ユーザーのログイン資格情報をキャッシュするPythonアプリケーションを構築しました。Redisは高可用性でスケーラブルなデータベースサーバーであり、秒間数千のトランザクションを実行することができます。アプリケーション内のRedisキャッシュメカニズムにより、バックエンドのデータベースサーバーへのトラフィックを大幅に削減することができます。Redisアプリケーションの詳細については、当社のRedisチュートリアルを参照してください。