Laravel sanctum logout не работает

Аутентификация через Laravel Sanctum

Sanctum — это пакет для Laravel, легковесная альтернатива существующим методам аутентификации (например, Laravel Passport) для использования в SPA и простых API. Ранее пакет назывался Airlock.

Я часто использую Laravel для создания API моих приложений, так это с ней это получается быстро и без большого количества кода. Но создание аутентификацией в ней (на мой взгляд) всегда была утомительной задачей.

Поэтому неудивительно, что увидев твит Тейлора Отвелла о Laravel Sanctum я захотел попробовать его для аутентификации в простом мобильном приложении.

Я кратко расскажу вам, как установить Sanctum, но если у вас возникнут какие-либо проблемы, обратитесь к документации. После установки Sanctum и создания с его помощью простой системы аутентификации я покажу вам, как использовать ее в приложении для iOS. Предполагается, что у вас есть базовые знания Swift и я не буду углубляться в создание интерфейса, который я покажу на своих скриншотах.

Читайте также:  Revelation как починить снаряжение

Установка

Для тестирования я создам новый проект Laravel. Надеюсь, что вы знаете, как это сделать, а если нет, то для получения дополнительной информации обратитесь к документации Laravel. Зайдите в каталог проекта и выполните следующие команды в своем терминале:

Теперь мы готовы погрузиться в проект и завершить настройку Sanctum.

В модели User используйте трейт HasApiTokens следующим образом:

Маршруты

Мы закончили настройку, теперь давайте создадим несколько маршрутов. Добавьте в ваш файл routes/api.php :

Пользователь будет использовать два этих маршрута для регистрации аккаунта и запроса токена (в основном, для входа в систему). Давайте создадим AuthController и напишем реализацию этих маршрутов. Запустите следующую строку в вашем терминале:

Откройте только что созданный файл app/Http/Controllers/API/AuthController.php и добавьте функцию register :

Вот пошаговое описание того, что делает этот код:

  1. Мы проверяем входящий запрос.
  2. Смотрим результат валидации. Если ошибка, то возвращаем ошибки в ответе.
  3. Хэшируем пароль и создаем нового пользователя.
  4. Создаем токен и сохраняем его, чтобы его можно было вернуть в ответе.

Как видите, при успешном запросе к этой конечной точке в теле ответа будет возвращен сгенерированный токен. Однако, чтобы убедиться, что нашим пользователям не нужно создавать новую учетную запись всякий раз, когда они хотят использовать приложение на другом устройстве, давайте создадим функцию, позволяющую нашим пользователям запрашивать токен:

Вот что делает этот код:

  1. Мы еще раз проверяем запрос и возвращаем ошибки, если валидация не удалась.
  2. Получаем первого User из нашей базы данных по указанному адресу электронной почты. Электронная почта уникальна, поэтому в лучшем случае нам вернёт одного пользователя.
  3. Если пользователь не существует (то есть адрес электронной почты был неправильным), или пароль не верен, то мы возвращаем ошибку, которую может подцепить наше приложение.
  4. Мы возвращаем сгенерированный токен.

Каркас нашей аутентификации готов! Давайте быстренько создадим маршрут, который позволит нам получить имя вошедшего в систему пользователя.

В файле routes/api.php добавьте следующий код:

Здесь мы используем мидлвар auth:sanctum . Это позволит удостовериться, что в заголовках запроса присутствует api-токен, и вернет ошибку, если его нет. Если запрос работает, то мы можем использовать $request->user() для получения доступа к пользовательской модели.

Я бы хотел много чего еще написать о том, что можно легко сделать с Sanctum, но воздержусь, чтобы иначе статья будет чрезмерно большой. Если вы хотите больше узнать о возможностях, например, добавление /возможностей/ и отзыв маркеров, обратитесь к документации.

Аутентификация

Пришло время протестировать наш API. Откроем Xcode и, на скорую руку, экран входа. После выполнения любой проверки на стороне клиента, которую вы захотите выполнить, передайте значения из полей форме регистрации в функцию, которую вы будете использовать для выполнения HTTP-запроса. Чтобы предоставить код, который можно использовать независимо от предпочитаемой вами архитектуры, я просто покажу вам, как простроить запрос для регистрацию пользователя. Убедитесь, что включили Content-Type заголовок application/json , иначе ваши запросы не будут выполнены.

Запрос на вход в систему очень похож, мы просто заменяем конечную конечную точку URL на /token и удаляем name из тела. Успешный запрос к любой из этих конечных точек приведет к следующему телу ответа:

После того, как ваш пользователь зарегистрирует свою учетную запись или войдет в систему, обязательно сохраните где-нибудь этот токен. Мы будем использовать его в следующем запросе, чтобы получить имя c бэкэнда:

Краткий обзор

Давайте вкратце рассмотрим то, что я объяснил в этой статье:

  • Мы настроили каркас Laravel и Sanctum для обработки аутентификации пользователей.
  • Мы можем создавать маршруты, используя мидлвар auth:sanctum , которое будет проверять токен, отправленный в заголовках, и давать нам доступ к соответствующей пользовательской модели.
  • Мы можем создавать запросы на использование нашего API.

Следующие шаги

Как я упоминал ранее, это лишь поверхностно рассматривает то, что можно сделать с Sanctum. Вы можете создавать токены с различными способностями, чтобы одни пользователи могли выполнять действия, а другие — нет. Или вы можете устанавливать срок годности токена и пользователю придется запрашивать новый. Sanctum все еще находится в бета-версии, поэтому возможно, что всё изменится и будут добавлены новые функции.

Надеюсь, эта статья дала вам некоторое представление о том, как Sanctum может быть простой альтернативой другим методам авторизации. Если вы разработчик мобильных приложений и никогда раньше не работали с Laravel, то я настоятельно рекомендую вам потратить на него немного времени. Вы сможете создать бэкэнд для своих приложений в кратчайшие сроки.

Наш Телеграм-канал — следите за новостями о Laravel.

Задать вопросы по урокам можно на нашем форуме.

Источник

Laravel sanctum logout не работает

what my problem is: \n

    \n
    auth:sanctum protected routes does not work they return (< "message" : "Unauthenticated" >) \n \n

what works: \n

    \n
    route \/api\/login works perfectly when given the correct password and email (it sends a response (<"message" : "Login successful">)) \n \n

my code snippets: \n

.env (it is only the part that is needed based on the docs I cant show the other because of security issues) \n

backend \n

UserController => for Authenticating \n

validator($request->all())->validate();\n\n $user = $this->create($request->all());\n\n $this->guard()->login($user);\n\n return response()->json([‘user’=> $user,\n ‘message’=> ‘registration successful’\n ], 200);\n >\n \/**\n * Get a validator for an incoming registration request.\n *\n * @param array $data\n * @return \\Illuminate\\Contracts\\Validation\\Validator\n *\/\n protected function validator(array $data)\n <\n return Validator::make($data, [\n 'name' =>[‘required’, ‘string’, ‘max:255′],\n ’email’ => [‘required’, ‘string’, ’email’, ‘max:255’, ‘unique:users’],\n ‘password’ => [‘required’, ‘string’, ‘min:4’, ‘confirmed’],\n ]);\n >\n\n \/**\n * Create a new user instance after a valid registration.\n *\n * @param array $data\n * @return \\App\\User\n *\/\n protected function create(array $data)\n <\n return User::create([\n 'name' =>$data[‘name’],\n ’email’ => $data[’email’],\n ‘password’ => Hash::make($data[‘password’]),\n ]);\n >\n protected function guard()\n <\n return Auth::guard();\n >\n\n public function login(Request $request)\n <\n $credentials = $request->only(’email’, ‘password’);\n\n if (Auth::attempt($credentials)) <\n \/\/ Authentication passed. \n return response()->json([‘message’ => ‘Login successful’], 200);\n >\n >\n\n public function logout()\n <\n Auth::logout();\n return response()->json([‘message’ => ‘Logged Out’], 200);\n >\n>\n \n

explode(‘,’, env(\n ‘SANCTUM_STATEFUL_DOMAINS’,\n ‘localhost,localhost:3000,127.0.0.1,127.0.0.1:8000. 1’\n )),\n ‘expiration’ => null,\n ‘middleware’ => [\n ‘verify_csrf_token’ => App\\Http\\Middleware\\VerifyCsrfToken::class,\n ‘encrypt_cookies’ => \\Illuminate\\Cookie\\Middleware\\EncryptCookies::class, \n ],\n\n];\n \n

[\n ‘guard’ => ‘web’,\n ‘passwords’ => ‘users’,\n ],\n ‘guards’ => [\n ‘web’ => [\n ‘driver’ => ‘session’,\n ‘provider’ => ‘users’,\n ],\n\n ‘api’ => [\n ‘driver’ => ‘token’,\n ‘provider’ => ‘users’,\n ‘hash’ => false,\n ],\n ],\n ‘providers’ => [\n ‘users’ => [\n ‘driver’ => ‘eloquent’,\n ‘model’ => App\\Models\\User::class,\n ],\n\n \/\/ ‘users’ => [\n \/\/ ‘driver’ => ‘database’,\n \/\/ ‘table’ => ‘users’,\n \/\/ ],\n ],\n ‘passwords’ => [\n ‘users’ => [\n ‘provider’ => ‘users’,\n ‘table’ => ‘password_resets’,\n ‘expire’ => 60,\n ‘throttle’ => 60,\n ],\n ],\n\n ‘password_timeout’ => 10800,\n\n];\n \n

Route::middleware(‘auth:sanctum’)->get(‘\/user’, function (Request $request) <\n return "protected route";\n>);\n\nRoute::post(«\/login»,»App\\Http\\Controllers\\UserController@login»);\n \n

cors.php (for development purposes I allowed all incoming requests to be processed) and (credentials are set to true) \n

‘paths’ => [‘*’],\n\n’allowed_methods’ => [‘*’],\n\n’allowed_origins’ => [‘*’],\n\n’allowed_origins_patterns’ => [],\n\n’allowed_headers’ => [‘*’],\n\n’exposed_headers’ => [],\n\n’max_age’ => 0,\n\n’supports_credentials’ => true,\n \n

protected $middleware = [\n \/\/ \\App\\Http\\Middleware\\TrustHosts::class,\n \\Fruitcake\\Cors\\HandleCors::class,\n \\App\\Http\\Middleware\\TrustProxies::class,\n \\Fruitcake\\Cors\\HandleCors::class,\n \\App\\Http\\Middleware\\PreventRequestsDuringMaintenance::class,\n \\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize::class,\n \\App\\Http\\Middleware\\TrimStrings::class,\n \\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull::class,\n ];\n\n ‘api’ => [\n \\Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful::class,\n ‘throttle:api’,\n \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n ],\n \n

Frontend \n

axios.defaults.withCredentials = true;\naxios.defaults.headers.common[‘X-Requested-With’] = ‘XMLHttpRequest’;\naxios.defaults.baseURL = ‘http:\/\/m.m\/api’;\n \n

Vue (this is the method that handles sending login requests) \n

what I get from the browser\nnetwork tab from chrome \n

this is what is stored in the browser as cookies\n(image) \n»» >

Источник

«logoutOtherDevices» doesn’t work with Laravel Sanctum #142

Comments

IlCallo commented May 15, 2020

  • Sanctum Version: 2.3.1
  • Laravel Version: 7.11.0
  • PHP Version: 7.4.4
  • Database Driver & Version: MariaDB 10.4.12

Description:

logoutOtherDevices doesn’t work when used in conjunction with Laravel Sanctum.
I’m trying to use it to logout a specific user from all its sessions, yet sessions aren’t invalidated.

Steps To Reproduce:

Login with an user, use tinker to run previous command, notice it produces no effect on currently active sessions.

The text was updated successfully, but these errors were encountered:

Ragash commented May 16, 2020

have you uncommented the middleware?

IlCallo commented May 17, 2020

Uncommenting the middeware actually breaks the logout.
Sanctum uses its own Middleware in which «AutenticatesSession» isn’t present, and that’s probably the reason it fails.
Maybe it could be added in its dynamic Middleware stack

Ragash commented May 17, 2020

replying in IT for semplicity:
se leggi le docs, se vuoi utilizzare quel metodo, sei costretto ad abilitare AutenticatesSession middleware.
Sono dipendenti, non c’è altro modo purtroppo.
E si, se lasci Sanctum allo stato brado, assume che il tuo logout sia effettuato sulla sua guard (dove il metodo non esiste) e quindi muore.
la soluzione è semplice:
nel tuo login controller specifica molto banalmente:

Ovviamente assumendo che tu stia utilizzando il tratto con cui lo scaffolding di laravel viene servito.
prova a fare backtracing dell’errore, cosi capisci bene dove si trova il culprit, le mie assunzione si basano principalmente su esperienza personale (anch’io c ho sbattuto il muso)

IlCallo commented May 18, 2020

It’s simpler for us to discuss in IT, but this won’t help next ones hitting this problem, so I’ll continue in EN.

I know the feature is tied with AuthenticatesSession, I opened this issue explicitly to make everyone aware this is a missing piece into Sanctum integration with Laravel.

I’m already using a custom logout (the default scaffolded by the Laravel UI doesn’t work with Sanctum) which specify the use of «web» guard, the problem arise only when I add the «AuthenticatesSession» middleware.

If anyone made Sanctum work with «logoutOtherDevices», please share your workaround. I’m gonna try to tackle the problem in some days anyway

Ragash commented May 18, 2020

Sure, good point.

I’ve relooked at your code and I think the problem is not related to logoutOtherDevice but to te fact that (I’m pretty sure) auth->setUset doesn’t touch the session at all.
You have to use the login method for that.
Maybe your test is failing cause there’s no session to invalidate?

IlCallo commented May 19, 2020 •

I’m trying to use it to logout a specific user from all its sessions, yet sessions aren’t invalidated.

The idea comes from here and is based on the fact that you logout all other sessions of the user, while you don’t have a current session. In this way you’re actively removing all its sessions.

It worked in 5.6, maybe something changed in the implementation on this regard in following versions (but missing AuthenticatesSession in Sactum middleware seems to be the culprit here).

I tested it with multiple incognito windows open, so I’m sure there were other sessions.

An alternative is to go with something similar to this one, but I’d prefer to avoid coupling session management with user persisted data on the DB. Especially when there is a built-in feature for this.

Good guide on how logoutOtherDevices works

Ragash commented May 19, 2020

Still, if you want to use logoutOtherDevice, you need that middleware.
why?
because the middleware take care of checking the remember_web cookie, and invalidate the request if data within it mismatchs.

the best way to solve your problem (i did that way right now in my app, just to test, and also because i would need that functionality) is to create your copy of AuthenticateSession specifying that the guard to use is «web» (the very same Sanctum uses for auth), like you would do in your login controller as i stated some days ago 🙂

And yes, even if Sanctum is a guard on it own, it’s wrap around the sessionGuard to functioning, so or you couple the session management (nope, don’t do that), or simply create your AuthenticateSession middleware as long the devs wont come out with a better solution (maybe a sanctum specific logoutOtherDevice method ? who knows)

hope this helps

Ragash commented May 19, 2020

Ah, i almost forgot.
Even if you are making a SPA, you would need AuthenticateSession in your web middleware anyway.

  1. when user load you app: for checking the remember_web cookie, and init stuff.
  2. in your api, yep, even if it may seems strange (it is to me), that’s because Sanctum on first-party SPA uses session for auths, so if you dont authenticate it, you cannot use it’s own function from an api 🙂

driesvints commented May 21, 2020

These features are incompatible unfortunately. If you can think of a good solution for this feel free to send in a pr. Thanks.

Abhi0725 commented Jul 17, 2020

@driesvints Shouldn’t issue be closed when it’s resolved? 🤔

IlCallo commented Jul 17, 2020

I guess what he meant was «won’t fix, but go ahead and give a try if you wish»

ghost commented Aug 9, 2020

I guess what he meant was «won’t fix, but go ahead and give a try if you wish»

This is not good news.

It’s a question that’s been bothering me as well.

Источник

Оцените статью