Есть три приложения (скажем, App-1, App-2 и App-3), которые используют SSO. В приложении 1 также реализован выход из обратного канала.
Проблема в том, что если приложение 1 в настоящее время выполнено в системе, и я делаю единый вход из приложения 2 или приложения 3, приложение 1 все равно будет входить в систему, даже если сеанс в Keycloak уже очищен.
Я пытался очистить файл cookie (который имеет два значения meeto и phpsessid), установив и удалив его через серверную часть, но он не вышел из системы.
Это мои настройки выхода из системы

Это моя функция выхода из обратного канала и очистки файлов cookie
function keycloak_backchannel_logout() {
// log_message('d', '=== BACKCHANNEL LOGOUT CALLED ===');
log_message('debug', '=== KEYCLOAK BACKCHANNEL LOGOUT CALLED ===');
// Only accessible if Keycloak is enabled
if (!$this->config->item('keycloak_enabled')) {
show_404();
}
log_message('debug', '=== CONDITION 1 PASS ===');
// Only accept POST requests
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
show_404();
}
log_message('debug', '=== CONDITION 2 PASS ===');
// Enhanced logging: Log IP address and request details
$client_ip = $this->input->ip_address();
$user_agent = $this->input->user_agent();
$request_time = date('Y-m-d H:i:s');
log_message('debug', '=== BACKCHANNEL LOGOUT PROCESS START ===');
log_message('debug', 'Backchannel logout called by Keycloak from IP: ' . $client_ip);
log_message('debug', 'Request time: ' . $request_time);
log_message('debug', 'User-Agent: ' . $user_agent);
// Log all POST data for debugging
$post_data = $this->input->post();
log_message('debug', 'POST data received: ' . json_encode($post_data));
try {
// Get logout_token from POST data
$logout_token = $this->input->post('logout_token');
if (!$logout_token) {
log_message('error', 'Backchannel logout: No logout_token provided');
log_message('error', 'Available POST keys: ' . implode(', ', array_keys($post_data)));
$this->output->set_status_header(400);
$this->output->set_output('Bad Request: Missing logout_token');
return;
}
// Log logout token preview (first 50 chars for security)
log_message('debug', 'Logout token received (preview): ' . substr($logout_token, 0, 50) . '...');
// Decode and validate logout_token
$token_data = $this->decode_logout_token($logout_token);
if (!$token_data) {
log_message('error', 'Backchannel logout: Invalid logout_token - validation failed');
$this->output->set_status_header(400);
$this->output->set_output('Bad Request: Invalid logout_token');
return;
}
// Log token data for debugging
log_message('debug', 'Logout token data: ' . json_encode($token_data));
// Extract session_id from token
$session_id = $token_data['sid'] ?? null;
if (!$session_id) {
log_message('error', 'Backchannel logout: No session_id in logout_token');
log_message('error', 'Available token claims: ' . implode(', ', array_keys($token_data)));
$this->output->set_status_header(400);
$this->output->set_output('Bad Request: No session_id in token');
return;
}
log_message('debug', 'Backchannel logout: Processing session_id: ' . $session_id);
// Clear current session first (like frontend logout)
$this->session->sess_destroy();
log_message('debug', 'Backchannel logout: Current session destroyed');
// Clear cookies like frontend logout does
$this->clear_keycloak_cookies();
log_message('debug', 'Backchannel logout: Keycloak cookies cleared');
// Also destroy session file by session_id (additional cleanup)
$this->destroy_session_by_id($session_id);
log_message('debug', 'Backchannel logout: Session destroyed successfully for session_id: ' . $session_id);
log_message('debug', '=== BACKCHANNEL LOGOUT COMPLETED ===');
// Return 200 OK to Keycloak
$this->output->set_status_header(200);
$this->output->set_output('OK');
} catch (Exception $e) {
// log_message('error', 'Backchannel logout error: ' . $e->getMessage());
// log_message('error', 'Stack trace: ' . $e->getTraceAsString());
log_message('debug', 'Backchannel logout error: ' . $e->getMessage());
log_message('debug', 'Stack trace: ' . $e->getTraceAsString());
$this->output->set_status_header(500);
$this->output->set_output('Internal Server Error');
}
}
private function clear_keycloak_cookies() {
log_message('info', '=== CLEARING KEYCLOAK COOKIES ===');
// Get cookie domain and path from config
$cookie_domain = $this->config->item('cookie_domain') ?: '';
$cookie_path = $this->config->item('cookie_path') ?: '/';
log_message('debug', 'Cookie domain: ' . $cookie_domain);
log_message('debug', 'Cookie path: ' . $cookie_path);
// List of cookies to clear (based on frontend logout behavior)
$cookies_to_clear = [
'keycloak_id_token',
'keycloak_id_token_exp',
'keycloak_access_token',
'keycloak_refresh_token',
'keycloak_state',
'keycloak_code_verifier',
'keycloak_nonce',
'meeto',
'PHPSESSID',
'user_data', // This might be the key!
'ci_session' // CodeIgniter session cookie
];
foreach ($cookies_to_clear as $cookie_name) {
// Clear cookie with different domain/path combinations
$cookie_configs = [
['domain' => $cookie_domain, 'path' => $cookie_path],
['domain' => $cookie_domain, 'path' => '/'],
['domain' => '', 'path' => $cookie_path],
['domain' => '', 'path' => '/'],
['domain' => '.pelindo.test', 'path' => '/'],
['domain' => '.pelindo.test', 'path' => $cookie_path]
];
foreach ($cookie_configs as $config) {
// Set cookie to expire in the past
setcookie($cookie_name, '', time() - 3600, $config['path'], $config['domain'], false, true);
log_message('debug', 'Cleared cookie: ' . $cookie_name . ' (domain: ' . $config['domain'] . ', path: ' . $config['path'] . ')');
}
}
log_message('debug', 'Deleting some of cookies');
delete_cookie('meeto');
delete_cookie('PHPSESSID');
log_message('debug', '=== KEYCLOAK COOKIES CLEARED ===');
}
Подробнее здесь: https://stackoverflow.com/questions/798 ... other-apps
Мобильная версия