78 lines
6.7 KiB
PHP
78 lines
6.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Middleware;
|
|
|
|
use Closure;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use App\Facades\UserContext;
|
|
use App\Models\User;
|
|
//очереди для чтения нотификаций
|
|
use Illuminate\Support\Facades\Redis;
|
|
use Laravel\Sanctum\PersonalAccessToken;
|
|
|
|
/**
|
|
* Глобальный посредник аутентификации на платформе Magic для всех роутов платформы
|
|
*/
|
|
class AuthenticateMagic
|
|
{
|
|
/**
|
|
* Handle an incoming request.
|
|
*
|
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
|
*/
|
|
public function handle(Request $request, Closure $next): Response
|
|
{
|
|
|
|
//TODO ПРОВЕРИТЬ
|
|
//Если сессия не стартовала возможно пользователь сразу обращается к api ендпоинту (ПРОВЕРИТЬ)
|
|
if (session()->isStarted()) {
|
|
if (session()->has('_auth_login')) {
|
|
//гаврилов. получение токена
|
|
// $token = $request->user();
|
|
// $userId = User::where('login', $token->getAttributes()['samaccountname'][0])->get()->toArray()[0]['id'];
|
|
// $tokenExpires = PersonalAccessToken::where('tokenable_id', $userId)->get()->toArray()[0]['expires_at'];
|
|
// echo '<pre>'; var_dump(new \DateTime($tokenExpires)); echo'</pre>';
|
|
// echo '<pre>'; var_dump(PersonalAccessToken::where('tokenable_id', $userId)->get()->toArray()[0]['expires_at']); echo'</pre>';
|
|
//Если токен истекает менее через 60 минут, продлеваем его на 2 часа. Ситуации, что сессия протухла, а токен продолжает жить не может случиться, так как апи запросы с фронта отправляют куку аутентификации, которая проверяется при $this->authenticate. Если она протухла, возвратится 401 ошибку.
|
|
// if ($token->expires_at->diffInMinutes(now()) < 60) {
|
|
// $token->update(
|
|
// [
|
|
// 'expires_at' => now()->addHours(2)
|
|
// ]
|
|
// );
|
|
// }
|
|
|
|
//Через фасад устанавливаем все значения аутентифицированного пользователя, чтобы через этот же фасад можно было и любого места в приложении их получить.
|
|
UserContext::setUserLogin(session()->get('_auth_login'));
|
|
$userGroups = session()->get('_auth_groups');
|
|
UserContext::setUserADGroups($userGroups);
|
|
UserContext::setUserEmails($userGroups);
|
|
UserContext::setIsAdminFlag(session()->get('is_admin'));
|
|
//На этапе посредника мы не проводим повторное определение ролей пользователя, это было сделано в LoginController в процессе авторизации после успешной аутентификации. Здесь мы уже берем его доступы из таблицы с токенами
|
|
$user = User::where('login', UserContext::getUserLogin())->first();
|
|
UserContext::setUserId($user->id);
|
|
UserContext::setUserAppPermissions($user->tokens()->latest()->first()->abilities['permissions']);
|
|
#Гаврилов
|
|
//Насксолько я помню, это связано с механизмом получения нотификаций на фронте (через отдельный компонент React) на случай, если нотификации формируются на бэке и должны читаться фронтом сразу при рендеринге. Обычно, нотификации формируются после запроса с фронта, например, при fetch запросе на отправку заявки на такси и сразу же рендерятся на этой же странице после выполнения fetch запроса, но бывают ситуации, когда пользователя с бэке редиректит на другую страницу, в результате чего тяряется "контекст" нотификаций. Я как-то настраивал чтение редис очередей на любой странице, чтобы при рендеринге любой страницы сразу проверялась есть ли непрочитенная нотификация. Если есть - она читается, отображается и удаляется из очереди. Но может конкретно строка ниже связана с тестированием , уже не помню
|
|
Redis::setex('notifications', 60, 123);
|
|
return $next($request);
|
|
} else {
|
|
//Получаем адрес предыдущей страницы, на которую хотел попасть пользователь, чтобы направить его после успешной аутентификации на этот адрес
|
|
$prevPageUrl = explode('/', $_SERVER['REDIRECT_URL']);
|
|
//Удаляем из URL редиректа пустые сегменты и сегмент с названием приложения (оно подставляется при редиректе само)
|
|
unset($prevPageUrl[0], $prevPageUrl[1]);
|
|
//Кладем в сессию адрес страницы. только если это не страница выхода, иначе после аутентификации пользователя сразу выбросит
|
|
session()->put('_auth_prev_page', implode('/', $prevPageUrl) == 'logout' ? '/menu' : implode('/', $prevPageUrl));
|
|
return redirect('/login');
|
|
//редирект на страницу login с сообщением об ошибке
|
|
}
|
|
} else {
|
|
return redirect('/login');
|
|
//redirect на страницу login после которой точно сессия застартует, так как это webроут, а не api
|
|
}
|
|
// return $next($request);
|
|
}
|
|
}
|