добавил контроллер аутентификации, который срабатывает после ввода логина пароля (да, я знаю, что назвать надо было по другому)

This commit is contained in:
vasya
2026-03-13 18:45:49 +03:00
parent b68611c31c
commit 4dc1c09693
2 changed files with 323 additions and 0 deletions
+246
View File
@@ -0,0 +1,246 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use LdapRecord\Models\ActiveDirectory\User as LdapUserInfo;
use App\Models\User;
use App\Facades\UserContext;
use App\Services\AuthorizationService;
use App\Services\ApiResponder;
use App\Dto\ApiResponseDto;
class LoginController extends Controller
{
#Гаврилов
//КОГДА ПЕРЕЙДЕМ НА ГРУППЫ, ПОМЕНЯТЬ НА АДМИНСКУЮ ГРУППУ? ИЛИ ОСТАВИТЬ РАССЫЛКУ?
//ПЕРЕНЕСИ В .ENV И ВНИЗУ ПО КОДУ ГДЕ ОБРАЩАЕШЬСЯ К ЭТОМУ СВОЙСТВУ КЛАССА ПЕРЕПИШИ НА ПОЛУЧЕНИЕ СВОЙСТВА ИЗ ПЕРЕМЕННОЙ ОКРУЖЕНИЯ
/**
* @var string почтовая рассылка, куда входят админы
*/
private $adminGroup = '# Magic_admins';
/**
* @var array массив групп, которые не должны участвовать в авторизации пользователя и поэтому могут не храниться
*/
#Гаврилов
//ИСПОЛЬЗУЙ МАССИВ НИЖЕ, ЧТОБЫ УДАЛЯТЬ ГРУППЫ И НЕ ХРАНИТЬ ИХ В ПРОФИЛЕ ПОЛЬЗОВАТЕЛЯ. ИЛИ ЗАБИТЬ ХЕР И ХРАНИТЬ ВСЕ? ТОГДА УДАЛИ МАССИВ НИЖЕ
private $unnecessaryGroups = array(
'MCO.',
'ARSNOVA.',
'CHATBOT.',
'FOA_PROJECTS.',
'MAXOPTRA.',
'WEBSIGNER.',
'ECM.',
'BASIS.',
'MCO_DOCUMENT.',
'FACTOR.',
'BIP.',
'NKK.',
'CHATS.',
'IB_BSC.',
'DASHAAI.',
'VDI.',
'CTX',
'AP.AE.',
'Way4',
'sg.',
'AD.TEDDY',
'AP.APPV_',
'AP.BI_',
'AP.Citrix_',
'AP.CSD_',
'AP.EFK_',
'AP.FlexiCapture_',
'AP.HPSM.ACCESS.1',
'AP.HPSM.ACCESS.3',
'AP.HPSM.APPR_BR.Collection.',
'AP.HPSM.APPR_BR.CS.',
'AP.HPSM.ACCESS.CC',
'AP.HPSM.ACCESS.123',
'AP.HPSM.ACCESS.1.2',
'AP.HPSM.APPR',
'AP.OCP',
'AP.IBS_',
'AP.Intranet_',
'AP.Intranet.',
'AP.Jenkins_',
'AP.Kibana.',
'AP.LICA.',
'AP.MailSteam.',
'AP.MCO_',
'AP.MDW.',
'AP.POCHTA_',
'AP.PREPROD',
'AP.Prometheus',
'AP.RDS_',
'AP.SAS_',
'AP.Seguranzza_',
'AP.TEST.LICA.',
'AP.Test.MCO_',
'AP.TEST',
'App_',
'BTA_',
'Calculations ',
'Cards_',
'CC.',
'CCS_',
'Citrix',
'Collection_HR_',
'Collection_All',
'CS_',
'CSD_',
'DA_',
'DB.',
'DB_',
'Deny_',
'Diasoft ',
'Digital ',
'DOR_',
'ECM_',
'FS.',
'FW.',
'INFO_',
'MDC.',
'NRM_Collection',
'PFA.',
'RenTest_',
'ReportingGroup ',
'RS.',
'SG.',
'SP.',
'SRV',
'SRVFI09_',
'SSO_',
'test',
'TR_',
'WWW_',
'MailStream',
'SRVTST',
);
public function __construct(private AuthorizationService $authorizationService, private ApiResponder $apiResponder) {}
#Гаврилов
//ПЕРЕИМЕНУЙ КОНТРОЛЛЕР НА AUTHcoNTROLLER
/**
* Метод завершения пользовательской сессии
*
* @return void
*/
public function logout()
{
//Удаляем все sanctum токены пользователя. Удаление всех токенов приведет к выходу пользователя со всех устройств, где он был залогинен в Magic
User::where('login', UserContext::getUserLogin())->first()->tokens()->delete();
session()->invalidate();
#Гаврилов
//ВЫЗОВ СКРИПТА НА СТАРОМ МЭДЖИКЕ ДЛЯ УДАЛЕНИЯ КУК АУТЕНТИФИКАЦИИ (ЛОГИН И ГРУППЫ)
return redirect('/login');
}
#Гаврилов
//РАЗНЕСИ ЛОГИКУ МЕЖДУ МЕТОДАМИ, А ТО ПОКА ВСЯ ЛОГИКА В ОДНОМ МЕТОД LDAPCHECK
public function ldapCheckUser(Request $request)
{
if ($request->_auth_login) {
if (Auth::attempt([
'samaccountname' => $request->_auth_login,
'password' => $request->_auth_password,
])) {
$userGroups = $this->getUserGroups($request->_auth_login);
session()->put('_auth_login', $request->_auth_login);
session()->put('_auth_groups', $userGroups);
//Если пользователь зашел впервые - записываем его логин в таблицу users. Она нужна для корректного взаимодействия с пакетом Sanctum
$user = User::firstOrCreate(
['login' => $request->_auth_login],
);
//Удаляем все предыдущие sanctum токены пользователя
User::where('login', $request->_auth_login)->first()->tokens()->delete();
//Определяем на какую страницу нужно бросить пользователя после успешной аутентификации. По умолчанию кидаем в меню
$redirectUrl = session()->has('_auth_prev_page') ? session()->get('_auth_prev_page') : ('/menu');
$isAdminFlag = in_array($this->adminGroup, $userGroups);
//Кладем в сессию информацию о том является ли пользователь админом
session()->put('is_admin', $isAdminFlag);
//Устанавливаем в пользовательский сервис параметры пользователя
UserContext::setUserLogin($request->_auth_login);
UserContext::setUserADGroups($userGroups);
UserContext::setUserEmails($userGroups);
UserContext::setIsAdminFlag($isAdminFlag);
$userPermissions = $this->authorizationService->getUserAppPermissions();
UserContext::setUserAppPermissions($userPermissions);
//Генерим Sanctum токен, чтобы поместить его в куки при редиректе
$token = $user->createToken('sanctum-token', [
'permissions' => $userPermissions
//Устанавливаем время жизни sanctum токена синхронно с временем жизни сессии из конфига
], now()->addHours(config('app.session_life_time') / 60))->plainTextToken;
return redirect($redirectUrl)
->withCookie('sanctum_token', $token, 60 * 24, '/', null, true, true);
} else {
#Гаврилов
//СООБЩЕНИЕ ОБ ОШИБКЕ ПРИ НЕУДАЧНОЙ АУТЕНТИФИКАЦИИ
return redirect('/login');
}
}
}
/**
* Метод фонового обновления санктум токена при получении 401 ошибки в ответе api ендпоинта
*
* @param Request $request
* @return void
*/
public function silentRefreshUserSanctumToken(Request $request)
{
//Если сессия истекла - возвращаем 401 ошибку и редирект на /login в axios
if (!Auth::check()) {
$this->apiResponder->setDto(new ApiResponseDto(null, ['token_refresh' => false]));
return response()->json($this->apiResponder->error(), 401);
}
$token = $request->cookie('sanctum_token');
$accessToken = \Laravel\Sanctum\PersonalAccessToken::findToken($token);
//Если токен "протух" - продлеваем его на час
if (now()->diffInMinutes($accessToken->expires_at, false) < 1) {
$accessToken->update(
[
'expires_at' => now()->addHours(1)
]
);
$this->apiResponder->setDto(new ApiResponseDto(null, ['token_refresh' => true]));
return response()->json($this->apiResponder->success());
} else {
//Если токен еще "свежий" - значит причина 401 ошибки в чем-то другом. Не обновляем токен, просто возвращаем 401 ошибку и редирект на /login в axios
$this->apiResponder->setDto(new ApiResponseDto(null, ['token_refresh' => false]));
return response()->json($this->apiResponder->error(), 401);
}
}
/**
* Метод получает группы пользователя из ldap
*
* @param string $userLogin логин пользователя, чьи группы получаем
* @return array
*/
public function getUserGroups($userLogin)
{
$userGroups = [];
$ldapUser = LdapUserInfo::findBy('samaccountname', $userLogin);
$ldapUser->memberOf;
if (isset($ldapUser->memberOf)) {
foreach ($ldapUser->memberOf as $ldapGroupInfo) {
$CN_group = substr($ldapGroupInfo, 0, stripos($ldapGroupInfo, ","));
$groupName = str_replace(array('CN=', '\\'), array('', ''), $CN_group);
$clearGroupName = trim($groupName);
if ($clearGroupName && $clearGroupName == str_replace($this->unnecessaryGroups, '', $clearGroupName)) {
$userGroups[] = $clearGroupName;
}
}
}
return $userGroups;
}
}