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 です。
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_DRIVER を
redis に変更しました。オンラインで試してみましたが、機能しませんでした。phpCAS によって
$_SESSION 変数に加えられた変更は、redis に書き込まれませんでした。何が起こっているのでしょうか。
session_set_save_handler の使用法が想像どおりではないことがわかりました。つまり、Laravel のセッションは実際には php の # を変更していませんでした。 # #$_SESSION
の読み取りおよび書き込みロジックについては、$_SESSION
を直接操作するか、デフォルトの動作 (ローカル ファイルの読み取りおよび書き込み) に従います。 そうですね、幸いなことに、Laravel のいくつかの SessionDrivers は
インターフェースを実装しています。これを自分たちで session_set_save_handler
:<pre class="brush:php;toolbar:false">session_set_save_handler(app(StartSession::class)->getSession($request)->getHandler());</pre>
万と呼ぶことができます。エラー!
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\DatabaseSessionHandler
の destroy
メソッドが $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 は挿入ではなく更新を実行します。これは、セッション データをセッション テーブルに書き込むことができないことを意味します。 実際には、セッション ラッパーを自分で作成して処理する以外に方法はありません。
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! になります。