ピットでの共有: phpCAS の Laravel 統合プロセス

藏色散人
リリース: 2021-09-19 16:54:03
転載
1831 人が閲覧しました

Laravel の次のチュートリアル コラムでは、Laravel に統合された phpCAS の落とし穴を共有します。それが必要な友人の役に立てば幸いです。

Laravel は phpCAS を統合します。落とし穴に関する注意事項

CAS は現在人気のシングル サインオン プロトコルです。公式はクライアント側 phpCAS の php バージョンを提供しています。これまでのところ、そのコーディング スタイルは PEAR 時代のままであり、名前空間も使用していません。幸いなことに、phpCAS はコンポーザーの導入をサポートしており、いくつかの Laravel プロジェクトの導入は問題なく完了しましたが、ここ 2 日間で、プロジェクトを単一マシンから複数マシンのデプロイメントにデプロイする必要がありました。ここで落とし穴を踏んでしまったので、ここに記録しておきます。

コールバック ピット

認証のために CAS サーバーにジャンプすると、着信コールバック アドレスにポート 8080 が追加されていることがわかりました。マルチマシン展開であるため、アクセス要求は最初にロード バランサー (Alibaba Cloud SLB) を通過してから Web サーバーに到達します。この 8080 は Web サーバーのリスニング ポートです。

そこで、phpCAS のロジックをトレースしてコールバック アドレスを生成し、次のコードを見つけました:

if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
    $server_port = $_SERVER['SERVER_PORT'];
} else {
    $ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']);
    $server_port = $ports[0];
}
ログイン後にコピー
そして、Alibaba Cloud の SLB はバックエンド サーバーに渡されません

XX -FORWARDED-PORT この http ヘッダーなので、phpCAS は $_SERVER['SERVER_PORT'] を取得します。これは nginx のポート 8080 です。

幸いなことに、phpCAS には、コールバック アドレスを手動で設定できる

setFixedServiceURL 関数が用意されています。

phpCAS::setFixedServiceURL($request->url());
ログイン後にコピー
コールバック アドレスは現在は正常ですが、コールバック アドレスが返されます。チケットが無効であることがクライアントに通知されます。

ログとコードの確認を続けたところ、ここで不注意だったことがわかりました。CAS サーバーがクライアントに戻ったとき、ページの URL は

http://client/login?ticket= でした。 xxxxx, クライアントがチケットを使用してサーバーとユーザー情報を交換する場合、チケットを申請するときにコールバック アドレス (サービス) も取得する必要があります。サーバーはチケットとサービスが一致しているかどうかを確認し、チケットを申請するときのサービスは http:///client/login である必要があるため、URL 内のチケット パラメータを削除する必要があります。

phpCAS::setFixedServiceURL($this->getUrlWithoutTicket($request));
ログイン後にコピー

getUrlWithoutTicket 関数は次のとおりです:

private function getUrlWithoutTicket(Request $request)
{
    $query = parse_query($request->getQueryString());
    unset($query['ticket']);
    $question = $request->getBaseUrl().$request->getPathInfo() == '/' ? '/?' : '?';

    return $query ? $request->url().$question.http_build_query($query) : $request->url();
}
ログイン後にコピー
セッションピット

これは、phpCAS Laravel の組み合わせピットです。 。

PHP はデフォルトでセッション ストレージをファイルとして保存するため、単一マシンを複数のマシンに変換するときに非常に重要な点は、セッション共有を処理することです。解決策も非常に簡単で、セッションの保存方法をファイルから redis/memecache/database などに変更するだけです。

Laravel はこれらのドライバーをデフォルトで提供するので、喜んで

.env ファイルを変更し、SESSION_DRIVERredis に変更しました。オンラインで試してみましたが、機能しませんでした。phpCAS によって $_SESSION 変数に加えられた変更は、redis に書き込まれませんでした。何が起こっているのでしょうか。

そこで、Laravel のセッション実装に従ってみたところ、セッションの読み取りおよび書き込みロジックを登録するための

session_set_save_handler の使用法が想像どおりではないことがわかりました。つまり、Laravel のセッションは実際には php の # を変更していませんでした。 # #$_SESSION の読み取りおよび書き込みロジックについては、$_SESSION を直接操作するか、デフォルトの動作 (ローカル ファイルの読み取りおよび書き込み) に従います。 そうですね、幸いなことに、Laravel のいくつかの SessionDrivers は

SessionHandlerInterface

インターフェースを実装しています。これを自分たちで session_set_save_handler <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">session_set_save_handler(app(StartSession::class)-&gt;getSession($request)-&gt;getHandler());</pre><div class="contentsignin">ログイン後にコピー</div></div>万と呼ぶことができます。エラー!

session_write_close(): Session callback expects true/false return value
ログイン後にコピー

Laravel コードを追跡した結果、redis ドライバーの親クラス

Illuminate\Session\CacheBasedSessionHandler

write メソッドが void を返すことがわかりました。 。そこで、それを修正するために PR を送信しましたが、拒否されるとは予想していませんでした。誰かが以前に修正したのに、サーバーが停止する可能性があると言って元に戻したことが判明しました。しかし、私は修正しませんでした。具体的な問題が見つからない。 まあ、memcache と redis は両方ともこの親クラスを継承しているため、代わりにデータベースを試す必要があります。

今回は

session_write_close

エラーは報告されませんが、CAS ログインに依然として問題があり、CAS サーバーとコールバック URL の間を飛び続けます。そこで、すべてのログとコードを追跡したところ、データベース ドライバー クラス Illuminate\Session\DatabaseSessionHandlerdestroy メソッドが $this->exists## を削除していないことがわかりました。セッションを破棄した後 # 属性は false としてマークされ、phpCAS のロジックは renameSession

$old_session = $_SESSION;
session_destroy();
$session_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $ticket);
session_id($session_id);
session_start();
$_SESSION = $old_session;
ログイン後にコピー
結果は $_SESSION = $ old_session; 対応する操作セッション テーブルの SQL は挿入ではなく更新を実行します。これは、セッション データをセッション テーブルに書き込むことができないことを意味します。

実際には、セッション ラッパーを自分で作成して処理する以外に方法はありません。

上記の 2 つの状況から、write メソッドの呼び出し時に true を返すことができる限り、redis ドライバーの方が扱いやすいことがわかります。したがって、コードは次のとおりです

namespace App\Services;

use SessionHandlerInterface;

class MySession implements SessionHandlerInterface
{
    /**
     * @var SessionHandlerInterface
     */
    protected $realHdl;

    /**
     * Session constructor.
     * @param SessionHandlerInterface $realHdl
     */
    public function __construct(SessionHandlerInterface $realHdl)
    {
        $this->realHdl = $realHdl;
    }

    public function close()
    {
        return $this->realHdl->close();
    }

    public function destroy($session_id)
    {
        return $this->realHdl->destroy($session_id);
    }

    public function gc($maxlifetime)
    {
        return $this->realHdl->gc($maxlifetime);
    }

    public function open($save_path, $name)
    {
        return $this->realHdl->open($save_path, $name);
    }

    public function read($session_id)
    {
        return $this->realHdl->read($session_id) ?: '';
    }

    public function write($session_id, $session_data)
    {
        $this->realHdl->write($session_id, $session_data);

        return true; // 这里
    }
}
ログイン後にコピー
そして

session_set_save_handler

を呼び出して

session_set_save_handler(new MySession(app(StartSession::class)->getSession($request)->getHandler()));
ログイン後にコピー
Done! になります。

以上がピットでの共有: phpCAS の Laravel 統合プロセスの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:segmentfault.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート