CAS kini merupakan protokol log masuk tunggal yang popular Setakat ini , Setakat ini, gaya pengekodannya kekal dalam era PEAR, tanpa menggunakan ruang nama pun. Nasib baik, phpCAS menyokong pengenalan komposer, dan saya telah melakukan beberapa pengenalan projek Laravel tanpa sebarang masalah, dalam dua hari yang lalu, projek perlu diubah daripada penggunaan mesin tunggal kepada penggunaan berbilang mesin langkah pada beberapa perangkap di sini saya akan merakam mereka di sini.
Callback Pit
Apabila melompat ke Pelayan CAS untuk pengesahan, kami mendapati port 8080 telah ditambahkan pada alamat panggil balik masuk. Oleh kerana ia adalah penggunaan berbilang mesin, permintaan akses akan mula-mula melalui pengimbang beban (Alibaba Cloud SLB) dan kemudian mencapai pelayan web, dan 8080 ini ialah port mendengar pelayan web.
Jadi saya mengesan logik phpCAS untuk menjana alamat panggil balik dan menemui sekeping kod ini:
if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) { $server_port = $_SERVER['SERVER_PORT']; } else { $ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']); $server_port = $ports[0]; }
SLB Alibaba Cloud tidak menghantar pengepala http ini ke pelayan hujung belakang X-FORWARDED-PORT
. Oleh itu, phpCAS akan mendapat $_SERVER['SERVER_PORT']
, iaitu port 8080 nginx.
Nasib baik, phpCAS menyediakan fungsi setFixedServiceURL
, yang membolehkan kami menetapkan alamat panggilan balik secara manual:
phpCAS::setFixedServiceURL($request->url());
Alamat panggil balik adalah perkara biasa sekarang, tetapi ia kembali daripada Pelayan CAS ke pelanggan saya diberitahu bahawa tiket itu tidak sah.
Terus menyemak log dan kod, saya mendapati bahawa saya cuai di sini Apabila Pelayan CAS kembali kepada pelanggan, url halaman adalah http://client/login?ticket=xxxxx
, dan pelanggan perlu membawanya bersamanya. apabila menggunakan tiket untuk bertukar-tukar maklumat pengguna dengan pelayan Alamat panggilan balik (perkhidmatan) semasa memohon tiket, pelayan akan mengesahkan sama ada tiket dan perkhidmatan adalah konsisten, dan perkhidmatan semasa memohon tiket hendaklah http://client/login
, jadi. kita perlu mengalih keluar parameter tiket dalam url.
phpCAS::setFixedServiceURL($this->getUrlWithoutTicket($request));
getUrlWithoutTicket
Fungsinya adalah seperti berikut:
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(); }
Session Pit
Ini ialah gabungan pit phpCAS Laravel, yang membuatkan anda hilang sabar .
Kaedah storan lalai PHP untuk sesi ialah fail, jadi perkara yang sangat penting apabila menukar satu mesin kepada berbilang mesin adalah untuk mengendalikan perkongsian sesi. Penyelesaiannya juga sangat mudah, iaitu menukar kaedah penyimpanan Sesi daripada fail kepada redis/memecache/pangkalan data, dsb.
Laravel menyediakan pemacu ini secara lalai, jadi saya teruja menukar fail .env
dan menukar SESSION_DRIVER
kepada redis
. Saya mencubanya dalam talian dan mendapati ia tidak berfungsi Perubahan yang dibuat oleh phpCAS kepada pembolehubah $_SESSION
tidak ditulis kepada redis.
Jadi saya mengikuti pelaksanaan Sesi Laravel dan mendapati bahawa ia bukanlah penggunaan session_set_save_handler
yang dibayangkan untuk mendaftar logik membaca dan menulis Sesi Dengan kata lain, Sesi Laravel sebenarnya tidak mengubah suai pembacaan dan penulisan PHP $_SESSION
Logik, kendalikan terus $_SESSION
atau ikut tingkah laku lalai (baca dan tulis fail tempatan).
Nah, mujurlah, beberapa Laravel SessionDriver telah melaksanakan antara muka SessionHandlerInterface
, dan kami boleh memanggilnya sendiri session_set_save_handler
:
session_set_save_handler(app(StartSession::class)->getSession($request)->getHandler());
Saya tidak pernah menjangka akan melaporkan ralat!
session_write_close(): Session callback expects true/false return value
Saya mengesan kod Laravel dan mendapati bahawa kaedah IlluminateSessionCacheBasedSessionHandler
kelas induk pemandu redis write
mengembalikan void
. Jadi saya menyerahkan PR untuk membetulkannya, tetapi saya tidak menjangkakan ia akan ditolak. t mencari isu khusus.
Nah, memcache dan redis kedua-duanya mewarisi kelas induk ini, jadi saya akan cuba pangkalan data sebaliknya.
Kali ini session_write_close
tiada ralat dilaporkan, tetapi masih terdapat masalah dengan log masuk CAS, dan ia terus melompat antara pelayan CAS dan url panggil balik. Jadi saya mengejar semua log dan kod dan mendapati bahawa kaedah IlluminateSessionDatabaseSessionHandler
kelas pemacu pangkalan data destroy
tidak menandakan atribut $this->exists
sebagai false
selepas memusnahkan Sesi, dan phpCAS mempunyai logik renameSession
$old_session = $_SESSION; session_destroy(); $session_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $ticket); session_id($session_id); session_start(); $_SESSION = $old_session;
Akibatnya ialah $_SESSION = $old_session;
operasi sql yang sepadan pada jadual sesi melaksanakan kemas kini dan bukannya memasukkan, iaitu, data sesi tidak boleh ditulis ke jadual sesi!
Sebenarnya tiada cara lain selain menulis Pembungkus Sesi untuk mengendalikannya.
Daripada dua situasi di atas, pemacu redis lebih mudah dikendalikan, selagi ia boleh kembali benar apabila memanggil kaedah tulis. Jadi kodnya adalah seperti berikut
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; // 这里 } }
dan kemudian memanggil session_set_save_handler
menjadi
session_set_save_handler(new MySession(app(StartSession::class)->getSession($request)->getHandler()));
Selesai!