Функция cot_user_authorize в Cotonti
Описание функции cot_user_authorize
Функция выполняет аутентификацию пользователя. Она проверяет данные пользователя, его права, обновляет сессию, устанавливает куки, а также выполняет различные проверки, включая на бан, активность и доступность групп.
Функция cot_user_authorize проверяет данные пользователя, выполняет все необходимые проверки (активность, бан, права), генерирует уникальный токен и идентификатор сессии, обновляет данные пользователя в базе и устанавливает куки или сессии для пользователя.
Код функции:
const COT_USER_AUTH_ERROR_NOT_FOUND = 1;
const COT_USER_AUTH_ERROR_FORBIDDEN = 2;
const COT_USER_AUTH_ERROR_BANNED = 3;
/**
* Authorize user
*
* @param int|array $id User ID or user data
* @param ?bool $remember Remember user authorization
* @return array{error?: int, success?: true}
*
* @todo move cot\User\UserService in future)
* @todo May be we should optionally fill user data like in system/common.php on line 336
* It can be useful if we will not redirect user after login, may be we should redirect anyway
*/
function cot_user_authorize($id, $remember = null)
{
if ($remember === null && Cot::$cfg['forcerememberme']) {
$remember = true;
}
if (is_array($id) && isset($id['user_id']) && isset($id['user_password'])) {
$user = $id;
$id = $user['user_id'];
} else {
$id = is_numeric($id) ? (int) $id : 0;
if ($id <= 0) {
return ['error' => COT_USER_AUTH_ERROR_NOT_FOUND];
}
$user = Cot::$db->query(
'SELECT user_id, user_password, user_maingrp, user_banexpire, user_sid, user_sidtime, '
. 'user_passsalt, user_passfunc FROM ' . Cot::$db->users . ' WHERE user_id = ? LIMIT 1',
$id
)->fetch();
if (empty($user)) {
return ['error' => COT_USER_AUTH_ERROR_NOT_FOUND];
}
}
$user['user_id'] = (int) $user['user_id'];
$user['user_maingrp'] = (int) $user['user_maingrp'];
cot_fillGroupsForUser($user);
if (empty($user['groups']) || array_intersect([COT_GROUP_DEFAULT, COT_GROUP_GUESTS], $user['groups'])) {
return ['error' => COT_USER_AUTH_ERROR_FORBIDDEN];
}
if (in_array(COT_GROUP_INACTIVE, $user['groups'], true)) {
if (!isset(Cot::$cfg['users']['inactive_login']) || !Cot::$cfg['users']['inactive_login']) {
return ['error' => COT_USER_AUTH_ERROR_FORBIDDEN];
}
}
if (in_array(COT_GROUP_BANNED, $user['groups'], true)) {
return ['error' => COT_USER_AUTH_ERROR_BANNED];
}
$token = cot_unique(16);
$sid = hash_hmac('sha256', $user['user_password'] . $user['user_sidtime'], Cot::$cfg['secret_key']);
$updateSid = '';
if (
empty($user['user_sid'])
|| $user['user_sid'] !== $sid
|| $user['user_sidtime'] + Cot::$cfg['cookielifetime'] < Cot::$sys['now']
) {
// Generate new session identifier
$sid = hash_hmac('sha256', $user['user_password'] . Cot::$sys['now'], Cot::$cfg['secret_key']);
$updateSid = ', user_sid = ' . Cot::$db->quote($sid) . ', user_sidtime = ' . Cot::$sys['now'];
}
Cot::$db->query(
'UPDATE ' . Cot::$db->users . " SET user_lastip='" . Cot::$usr['ip'] . "', "
. 'user_lastlog = ' . Cot::$sys['now'] . ', user_logcount = user_logcount + 1, '
. ' user_token = ' . Cot::$db->quote($token) . " $updateSid WHERE user_id = ?",
$user['user_id']
);
// Hash the sid once more so it can't be faked even if you know user_sid
$sid = hash_hmac('sha1', $sid, Cot::$cfg['secret_key']);
$u = base64_encode($user['user_id'] . ':' . $sid);
/* === Hook === */
foreach (cot_getextplugins('users.authorize') as $pl) {
include $pl;
}
/* ===== */
if ($remember) {
cot_setcookie(
Cot::$sys['site_id'],
$u,
time() + Cot::$cfg['cookielifetime'],
Cot::$cfg['cookiepath'],
Cot::$cfg['cookiedomain'],
Cot::$sys['secure'],
true
);
unset($_SESSION[Cot::$sys['site_id']]);
} else {
$_SESSION[Cot::$sys['site_id']] = $u;
}
/* === Hook === */
foreach (cot_getextplugins('users.authorize.done') as $pl) {
include $pl;
}
/* ===== */
return ['success' => true];
}
Подробное описание каждого условия в теле функции
Установка значения переменной $remember:
if ($remember === null && Cot::$cfg['forcerememberme']) {
$remember = true;
}
Что проверяется?: Если переменная $remember не была передана в функцию и в конфигурации указано, что нужно принудительно активировать "запомнить меня" (значение Cot::$cfg['forcerememberme']), то переменная $remember будет установлена в true.
Зачем?: Это нужно, чтобы автоматически включить опцию "запомнить меня", если она задана в конфигурации, независимо от передачи этой опции в функцию.
Проверка и извлечение данных о пользователе:
if (is_array($id) && isset($id['user_id']) && isset($id['user_password'])) {
$user = $id;
$id = $user['user_id'];
} else {
$id = is_numeric($id) ? (int) $id : 0;
if ($id <= 0) {
return ['error' => COT_USER_AUTH_ERROR_NOT_FOUND];
}
$user = Cot::$db->query(
'SELECT user_id, user_password, user_maingrp, user_banexpire, user_sid, user_sidtime, '
. 'user_passsalt, user_passfunc FROM ' . Cot::$db->users . ' WHERE user_id = ? LIMIT 1',
$id
)->fetch();
if (empty($user)) {
return ['error' => COT_USER_AUTH_ERROR_NOT_FOUND];
}
}
Что проверяется?: Если передан массив с данными о пользователе, то используется этот массив, а ID извлекается из ключа user_id. Если передан только ID пользователя (целое число), выполняется запрос в базу данных для получения подробных данных пользователя.
Зачем?: Для аутентификации нужно сначала получить все данные пользователя, такие как пароль, группа и информация о сессии.
Приведение данных к целым числам:
$user['user_id'] = (int) $user['user_id']; $user['user_maingrp'] = (int) $user['user_maingrp'];
Что проверяется?: Преобразование значений user_id и user_maingrp в целые числа для предотвращения возможных ошибок с типами данных.
Заполнение групп пользователя:
cot_fillGroupsForUser($user);
Что делается?: Вызывается функция cot_fillGroupsForUser, чтобы получить и обновить информацию о группах, к которым принадлежит пользователь.
Проверка на принадлежность к запрещенным или гостевым группам:
if (empty($user['groups']) || array_intersect([COT_GROUP_DEFAULT, COT_GROUP_GUESTS], $user['groups'])) {
return ['error' => COT_USER_AUTH_ERROR_FORBIDDEN];
}
Что проверяется?: Если у пользователя нет групп или если он принадлежит к группе по умолчанию (COT_GROUP_DEFAULT) или к гостевой группе (COT_GROUP_GUESTS), то доступ запрещен. Возвращается ошибка COT_USER_AUTH_ERROR_FORBIDDEN.
Проверка на неактивность пользователя:
if (in_array(COT_GROUP_INACTIVE, $user['groups'], true)) {
if (!isset(Cot::$cfg['users']['inactive_login']) || !Cot::$cfg['users']['inactive_login']) {
return ['error' => COT_USER_AUTH_ERROR_FORBIDDEN];
}
}
Что проверяется?: Если пользователь находится в группе "Неактивные" (COT_GROUP_INACTIVE), то проверяется, разрешено ли входить неактивным пользователям. Если в конфигурации указано, что это не разрешено, то возвращается ошибка COT_USER_AUTH_ERROR_FORBIDDEN.
Проверка на бан пользователя:
if (in_array(COT_GROUP_BANNED, $user['groups'], true)) {
return ['error' => COT_USER_AUTH_ERROR_BANNED];
}
Что проверяется?: Если пользователь находится в группе "Забаненные" (COT_GROUP_BANNED), то доступ запрещен и возвращается ошибка COT_USER_AUTH_ERROR_BANNED.
Генерация токена и идентификатора сессии:
$token = cot_unique(16);
$sid = hash_hmac('sha256', $user['user_password'] . $user['user_sidtime'], Cot::$cfg['secret_key']);
Что делается?: Генерируется уникальный токен для пользователя и вычисляется хэш идентификатора сессии на основе пароля пользователя и времени сессии.
Проверка и обновление идентификатора сессии:
if (
empty($user['user_sid'])
|| $user['user_sid'] !== $sid
|| $user['user_sidtime'] + Cot::$cfg['cookielifetime'] < Cot::$sys['now']
) {
$sid = hash_hmac('sha256', $user['user_password'] . Cot::$sys['now'], Cot::$cfg['secret_key']);
$updateSid = ', user_sid = ' . Cot::$db->quote($sid) . ', user_sidtime = ' . Cot::$sys['now'];
}
Что проверяется?: Если текущий идентификатор сессии пустой или не совпадает с вычисленным значением, или если время жизни сессии истекло, то генерируется новый идентификатор сессии и обновляется его время.
Обновление данных пользователя в базе данных:
Cot::$db->query(
'UPDATE ' . Cot::$db->users . " SET user_lastip='" . Cot::$usr['ip'] . "', "
. 'user_lastlog = ' . Cot::$sys['now'] . ', user_logcount = user_logcount + 1, '
. ' user_token = ' . Cot::$db->quote($token) . " $updateSid WHERE user_id = ?",
$user['user_id']
);
Что делается?: Обновляются данные пользователя в базе: записывается его последний IP-адрес, время последнего входа, количество входов и новый токен. Также обновляется идентификатор сессии, если это необходимо.
Хэширование идентификатора сессии и подготовка данных для куки:
$sid = hash_hmac('sha1', $sid, Cot::$cfg['secret_key']);
$u = base64_encode($user['user_id'] . ':' . $sid);
Что делается?: Идентификатор сессии снова хэшируется для защиты и создается строка, которая будет использована для куки.
Установка куки, если выбрано "запомнить меня":
if ($remember) {
cot_setcookie(
Cot::$sys['site_id'],
$u,
time() + Cot::$cfg['cookielifetime'],
Cot::$cfg['cookiepath'],
Cot::$cfg['cookiedomain'],
Cot::$sys['secure'],
true
);
unset($_SESSION[Cot::$sys['site_id']]);
} else {
$_SESSION[Cot::$sys['site_id']] = $u;
}
Что делается?: Если выбрана опция "запомнить меня", устанавливается кука с данными пользователя, иначе данные сохраняются в сессию.
Выполнение плагинов после авторизации:
foreach (cot_getextplugins('users.authorize.done') as $pl) {
include $pl;
}
Что делается?: Выполняются плагины, связанные с завершением процесса авторизации, если таковые имеются.
Возврат успешного результата:
return ['success' => true];
Что делается?: Если все проверки прошли успешно и пользователь был авторизован, возвращается успех.
Комментарии (0)
Автор контента
Оффлайн
Administrator
Последняя авторизация: 05.07.2026 18:32
- Страница размещена: 21.01.2025 21:09
- Последнее обновление: 21.01.2025 21:09