Насколько мне известно, система авторизации на основе JWT обычно зарезервирована для SPA (вы знаете, одно представление, одно приложение React / Angular / Vue с одним раздутым файлом app.js), однако я пытаюсь использовать магию JWT с немного отдельным структурированным приложением.
Состав
Вместо того, чтобы обслуживать одно представление blade.php из моего приложения Laravel, которое объединяет одно приложение и экземпляр Vue, я пытаюсь обслужить ДВА отдельных представления blade.php, каждое из которых работает как свое собственное отдельное представление Vue SPA: для внешней стороны приложения (предварительная проверка ) и еще один для внутренней части приложения (после авторизации).
Текущее состояние приложения
Для обеспечения работы системы аутентификации моего приложения я использовал библиотеку Jwt-auth Таймона (красивая библиотека кстати) и связал все вместе на лицевой стороне с помощью (как говорилось ранее) Vue/Vuex. Все работает так, как ожидалось, в моих компонентах Register и Login я могу попасть в свой api, получить JWT в ответ, сохранить его локально, а затем добавить указанный токен в мои заголовки Axios, позволяя всем последующим запросам содержать этот токен.
Дилемма
Сейчас я на распутье. Маршрут / представление после авторизации, которое я хочу обслуживать, защищено специальным промежуточным программным обеспечением JWT, которое перенаправляет, если действительный токен не представлен:
Route::get('/home', 'Auth\HomeController@home')->middleware('jwt');
промежуточное ПО
class JWT
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
JWTAuth::parseToken()->authenticate();
return $next($request);
}
}
и мой просмотр до авторизации и все его маршруты защищены встроенным гостевым промежуточным программным обеспечением Laravel RedirectIfAuthenticated, которое теперь охраняется JWT:
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/home');
}
return $next($request);
}
}
Вопросов
Отсюда возникают следующие вопросы:
1) после успешной регистрации / входа в интерфейс и JWT сгенерирован, сохранен локально и в заголовках Axios, как мне затем перенаправить на мой маршрут после авторизации с этим доступным действующим токеном?
2) Как мне затем убедиться, что действительный JWT сохраняется и присутствует при попадании в гостевые маршруты для успешного перенаправления обратно на мой маршрут после авторизации?
Я бы предпочел хранить все перенаправления и проверки устойчивости на бэкэнде, если это возможно.
Тот же домен, установка / проект Laravel по умолчанию с Vue на интерфейсе @Lassi Uosukaimen
Итак, проблема в том, что у вас нет доступного токена после перенаправления на другую страницу? Или действительно просто обновляете ту же страницу?
Точнее, токен генерируется на бэкэнде и отправляется во внешний интерфейс для локального хранения (в хранилище браузера) и добавляется в заголовки axios, чтобы каждый последующий запрос ajax отправлялся с токеном @tobbr
Храните токен в файлах cookie, а не в локальном хранилище. Безопасность и т. д. Установите тайм-аут для JWT в соответствии с тайм-аутом для сеанса Laravel. Проверяйте, истек ли токен в промежуточном программном обеспечении для каждого запроса, если он истекает, перенаправьте их на страницу входа. Отправляйте токен-носитель из файла cookie с каждым последующим запросом axios.
есть ли способ хоть немного, удаленно, отчетливо показать это в коде? :} @О, Боже, почему
Я хочу, чтобы в каждом запросе был токен, даже от другого контроллера, как я могу это сделать?






Итак, есть несколько способов убедиться, что токен JWT доступен везде для Axios или для любого внешнего интерфейса.
Наиболее распространенный способ - сохранить токен либо в печенье, либо в веб-хранилище браузера (localStorage / sessionStorage).
Разница между localStorage и sessionStorage заключается в том, что данные, хранящиеся в localStorage, сохраняются во время сеансов браузера, sessionStorage очищается при завершении сеанса страницы.
По общему мнению, файлы cookie немного более безопасны, поскольку имеют меньший вектор атаки, хотя ни один из методов не является полностью безопасным. Если вы хотите углубиться, вы можете начать с чтения статьи это.
Чтобы получить более конкретную информацию о вашей проблеме, сначала вы хотите настроить хранилище токенов, используя один из методов, описанных выше, рекомендуемый метод - файлы cookie, вы можете найти примеры того, как это сделать с чистым Javascript здесь.
Теперь, когда у вас есть токен на каждой странице, вы можете перенаправить пользователя любым способом. Хотя я бы посоветовал вместо использования вашего собственного промежуточного программного обеспечения для аутентификации JWT вы можете использовать то, которое предоставляет библиотека JWT: jwt.auth.
Это промежуточное ПО будет автоматически отвечать кодами ошибок, если с токеном что-то не так, и если есть, оно вернет один из следующих HTTP-ответов:
token_not_providedtoken_expiredtoken_invaliduser_not_foundЕсли возвращается один из этих ответов (или если код состояния запроса равен 400), вы можете просто использовать интерфейс, чтобы перенаправить пользователя обратно на ваши маршруты до авторизации.
При входе в систему после сохранения токена в cookie используйте интерфейс для перенаправления на маршруты после авторизации.
Я знаю, вы сказали, что хотите сохранить логику перенаправления в бэкэнде, но на самом деле это не имеет смысла, когда вы, например, вызываете API при входе в систему, вы не можете одновременно вернуть токен и вызвать перенаправление в то же время только из серверной части.
ОБНОВИТЬ
Очень простой пример того, как вы можете пройти аутентификацию только с охранником и при этом получить токен для API. Заимствуя пример перенаправления из @Ohgodwhy, вы можете поместить следующее в промежуточное ПО RedirectIfAuthenticated.
public function handle($request, Closure $next, $guard = null)
if (Auth::guard($guard)->check()) {
if ((\Cookie::get('access_token') == null)) {
$cookie = \Cookie::make(
'access_token',
\JWTAuth::fromUser(Auth::user()),
config('session.lifetime'),
null,
$request->refeerer,
false, // to make the cookie available in javascript
false // to make the cookie available in javascript
);
return redirect('/home')->cookie($cookie);
} else {
return redirect('/home');
}
}
return $next($request);
}
Просто убедитесь, что ваш $redirectTo в app/Http/Controllers/Auth/LoginController.php настроен на путь, реализующий промежуточное ПО RedirectIfAuthenticated.
я имею в виду, не могу ли я? в моих методах register или login в моем бэкэнде, после успешной аутентификации и генерации токена, не могу ли я просто вызвать перенаправление на мой маршрут post-auth, добавив в настраиваемый заголовок, значением которого является токен?
Насколько мне известно, вместо того, чтобы возвращать cookie в ответ, вы можете использовать подход @Ohgodwhy, описанный для установки cookie из бэкэнда, тогда вам не нужно будет его возвращать.
да, но это все еще не отвечает на вопрос о перенаправлении на мой маршрут после авторизации с этим токеном, присутствующим либо в форме заголовка, либо в форме данных. И даже если я перенаправляю через интерфейс, как мне (в JS) сделать запрос с настраиваемым заголовком?
Ну, в таком случае, почему бы просто не изменить промежуточное ПО RedirectIfAuthenticated для перенаправления на ваши предварительные маршруты, если проверка защиты не удалась?
Чтобы уточнить, что я имею в виду, это использование встроенной защиты Laravels для обработки доступа к представлениям /post-auth и /pre-auth и использование JWT для обработки доступа к API.
ну, потому что для этого будут использоваться два устройства защиты аутентификации, а это, я считаю, довольно неэффективно. Я буду использовать встроенную защиту laravel для аутентификации, а затем, когда в post auth для доступа к любым маршрутам API, мне придется снова аутентифицироваться с JWT для выполнения последующих запросов ...
Не совсем так, поскольку вы можете использовать $token = JWTAuth::fromUser(Auth::user());, чтобы получить токен для пользователя, который прошел аутентификацию с помощью охранника. Это то, что JWT делает в фоновом режиме. Но если вы не хотите делать это таким образом, я полагаю, вам нужно сделать JWTAuth::setToken($request->cookie('access_token'))->authenticate(); в промежуточном программном обеспечении jwt вместо того, чтобы разбирать его из запроса.
если вы можете вкратце продемонстрировать логику аутентификации, реализующую встроенную защиту Laravel сначала, чтобы перейти от представления до авторизации к представлению после авторизации, а затем используя JWT до конца после авторизации (с его SPA), это было бы потрясающе
В итоге я реализовал метод, аналогичный твоему. проверьте ответ и критику, где вы видите недостатки
Я хочу, чтобы в каждом запросе был токен, даже от другого контроллера, как я могу это сделать?
При успешном входе в систему у вас будет токен, скажем, он называется $jwt_token.
Вы можете перенаправить на защищаемую страницу после авторизации и установить cookie в ответе:
return redirect('/home')->cookie(
'access_token', //name
$jwt_token, //value
config('session.lifetime'), //expiration in minutes (matches laravel)
config('app.url'), // your app url
true // HttpsOnly
);
Отсюда Axios может получить доступ к cookie путем анализа файлов cookie в документе и получения access_token.
let token = document.cookie.split(';') // get all your cookies
.find(cookie => cookie.includes('access_token')) // take only the one that matches our access_token name
.split('=')[1] // get just the value after =
// terrible code example above for you
Теперь вы можете использовать это в своих запросах Axios, добавив его в качестве значения для Bearer в заголовке Authorization:
Authorization: `Bearer ${token}`
Ваше промежуточное ПО JWT уже использует метод authenticate, и поэтому оно должно обрабатывать expiry в его нынешнем виде:
JWTAuth::parseToken()->authenticate();
Под капотом это попытается проверить срок действия токена на основе текущего TTL, установленного в файле config/jwt.php. Учитывая ваш рабочий процесс, я бы также blacklist токен, если он истекает. Вы можете добавить Event Listener, который прослушивает просроченные токены и помещает их в черный список, прослушивая Event::listen('tymon.jwt.expired');.
Пожалуйста, извините за любые синтаксические ошибки, проблемы с форматированием или орфографические ошибки, я на своем телефоне и позже отредактирую их, чтобы их исправить.
да, ваш подход к перенаправлению после входа в систему соответствовал тому, о чем я думал, однако промежуточное ПО JWT требует, чтобы токен был отправлен вместе с запросами на любой маршрут, который он защищает, поэтому, если я не могу перенаправить на /home при установке токена в заголовок или отправка токена каким-то образом, я никогда не достигну /home, просто перенаправляю обратно
Я хочу, чтобы в каждом запросе был токен, даже от другого контроллера, как я могу это сделать?
Итак, вот логика, которую я реализовал:
В моей функции входа в систему LoginController.php после успешной аутентификации и генерации JWT я возвращаю ответ с Json и новым файлом cookie, оба с переданным новым token:
public function login(Request $request)
{
$creds = $request->only(['email', 'password']);
if (!$token = auth()->attempt($creds)) {
return response()->json([
'errors' => [
'root' => 'Incorrect Credentials. Try again'
]
], 401);
}
return $this->respondWithToken($token);
}
protected function respondWithToken($token)
{
return response()->json([
'meta' => [
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60
]
], 200)
->withCookie(cookie('access_token', $token, auth()->factory()->getTTL()));
}
В моем гостевом промежуточном программном обеспечении RedirectIfAuthenticated проверяется наличие cookie, если он существует, setToken, который, в свою очередь, устанавливает Guard в режим аутентификации и всегда будет перенаправлять на /home, если токен доступен и действителен:
public function handle($request, Closure $next, $guard = null)
{
if ($request->hasCookie('access_token')) {
Auth::setToken($request->cookie('access_token'));
}
if (Auth::guard($guard)->check()) {
return redirect('/home');
}
return $next($request);
}
И в моем промежуточном программном обеспечении post-auth Routes я также setToken, и, если он действителен и существует, разрешит доступ, в противном случае будет выдан ряд ошибок JWT, которые просто перенаправляют на просмотр до авторизации:
public function handle($request, Closure $next)
{
JWTAuth::setToken($request->cookie('access_token'))->authenticate();
return $next($request);
}
Наконец, я решил обработать перенаправление во внешнем интерфейсе, так как я использую Axios, который, как обещано, основан и может гарантировать, что cookie будет установлен перед перенаправлением в режим пост-авторизации, поэтому никаких забавных дел не происходит! Ваше здоровье! Надеюсь, это поможет любому на пути к магии многостраничного СПА!
Оба эти приложения находятся в одном домене или в разных доменах?