5,3 паспорта и API-интерфейсы Laravel
Я использую Laravel Framework версии 5.3.9, свежая загрузка ничего не добавлена через композитора (кроме "laravel/passport": "^1.0"
).
Я сделал все то, что предложено в документах. Таблицы созданы, маршруты открыты, все работает нормально. Однако мне нужен паспорт для API.
Мои маршруты выглядят так:
+--------+----------+-----------------------------------------+----------------------+----------------------------------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+-----------------------------------------+----------------------+----------------------------------------------------------------------------+------------+
| | GET|HEAD | / | | Closure | web |
| | GET|HEAD | api/v1/users/register | api::users::register | App\Http\Controllers\Api\V1\SocialController@register | api,auth |
| | POST | oauth/authorize | | \Laravel\Passport\Http\Controllers\ApproveAuthorizationController@approve | web,auth |
| | GET|HEAD | oauth/authorize | | \Laravel\Passport\Http\Controllers\AuthorizationController@authorize | web,auth |
| | DELETE | oauth/authorize | | \Laravel\Passport\Http\Controllers\DenyAuthorizationController@deny | web,auth |
| | GET|HEAD | oauth/clients | | \Laravel\Passport\Http\Controllers\ClientController@forUser | web,auth |
| | POST | oauth/clients | | \Laravel\Passport\Http\Controllers\ClientController@store | web,auth |
| | PUT | oauth/clients/{client_id} | | \Laravel\Passport\Http\Controllers\ClientController@update | web,auth |
| | DELETE | oauth/clients/{client_id} | | \Laravel\Passport\Http\Controllers\ClientController@destroy | web,auth |
| | GET|HEAD | oauth/personal-access-tokens | | \Laravel\Passport\Http\Controllers\PersonalAccessTokenController@forUser | web,auth |
| | POST | oauth/personal-access-tokens | | \Laravel\Passport\Http\Controllers\PersonalAccessTokenController@store | web,auth |
| | DELETE | oauth/personal-access-tokens/{token_id} | | \Laravel\Passport\Http\Controllers\PersonalAccessTokenController@destroy | web,auth |
| | GET|HEAD | oauth/scopes | | \Laravel\Passport\Http\Controllers\ScopeController@all | web,auth |
| | POST | oauth/token | | \Laravel\Passport\Http\Controllers\AccessTokenController@issueToken | |
| | POST | oauth/token/refresh | | \Laravel\Passport\Http\Controllers\TransientTokenController@refresh | web,auth |
| | GET|HEAD | oauth/tokens | | \Laravel\Passport\Http\Controllers\AuthorizedAccessTokenController@forUser | web,auth |
| | DELETE | oauth/tokens/{token_id} | | \Laravel\Passport\Http\Controllers\AuthorizedAccessTokenController@destroy | web,auth |
+--------+----------+-----------------------------------------+----------------------+----------------------------------------------------------------------------+------------+
Все web
маршруты есть, нет api
связанные маршруты, так как Passport не предоставляет ничего подобного из коробки.
Сам API предназначен для использования доверенным клиентом, он предназначен для мобильного приложения, которое требует входа в систему, однако вход в систему будет проходить через несколько шагов.
Когда пользователь получает доступ к /register
маршрут, сам процесс регистрации довольно прост: зайдите в учетную запись пользователя на Facebook, возьмите несколько полей - электронная почта, идентификатор на Facebook, назовите фотографию профиля, и с этого момента пользователи считаются зарегистрированными. Но пользователь НЕ будет входить через Facebook(это очень важный аспект). Потребительскому приложению будет выдан токен, который будет использовать этот токен для доступа к различным конечным точкам API (для которых требуется токен).
Так что все сводится к этому. Мне нужно выдать токен доступа к потребительскому приложению, которое обращается к API. У самого API будет только один клиент, то есть само мобильное приложение. Пользователи, которые используют приложение, не считаются клиентами API, а являются клиентами самого мобильного приложения.
Пока что Passport - это головная боль, с которой приходится сталкиваться, когда речь идет о реализации вещей, связанных с API, либо я не могу понять, как заставить его работать должным образом.
Я создал тестовый клиент в oauth_clients
таблица, которая выглядит так:
Я использую Почтальон для доступа api/v1/users/register
маршрут, который имеет auth
промежуточное программное обеспечение со следующим JSON application/json
{
"grant_type" : "authorization_code",
"client_id" : 5,
"client_secet": "y5dvPIOxQJOjYn7w2zzg4c6TRrphsrNFWbG4gAUL"
}
Что, конечно, приведет к
{"error":"Unauthenticated."}
Это имеет смысл. Из чистого любопытства я изменил /register
маршрут к этому:
Route::group([
'middleware' => [
],
], function ()
{
Route::group([
'prefix' => 'users',
'as' => 'users::',
], function ()
{
// Route::get('/register', ['as' => 'register', 'uses' => 'Api\V1\SocialController@register',]);
Route::post('/register', ['as' => 'register', 'uses' => '\Laravel\Passport\Http\Controllers\AccessTokenController@issueToken',]);
});
});
С тем же json
как прежде. Это привело к {"error":"invalid_client","message":"Client authentication failed"}
,
Я отследил функцию, которая, я думаю, обрабатывает validateClient
участие в vendor/league
oauth2-server / src / Grant / AbstractGrant`.
$client
нулевой. Теперь это может или не может быть связано с паспортом, так как документации по нему, скорее всего, не хватает, и мысль о копании в монстре пакета, чтобы отследить ошибку, которая может быть в значительной степени из-за того, что я что-то не сделал правильно, меня не поражает как хорошая идея, у меня нет вариантов. Честно говоря, я даже не знаю, в чем проблема.
Действительно, на данный момент любой вид, указывающий в правильном направлении, более чем приветствуется.
Часть в вопросах
2 ответа
Проблема с паспортом Laravel 5.3 заключается в том, что в отличие от предыдущей библиотеки OAuth 2.0 Server для Laravel, предлагаемой lucadegasperi, у нее нет API для непосредственного создания клиентов. Так как будто теперь клиент может быть сделан только через интерфейс. К вашему сведению, мы хотели использовать паспорт laravel исключительно для нашего мобильного приложения, поэтому при создании и регистрации пользователя у нас будет только EMAIL & Password, а в некоторых случаях только Facebook UserID для входа в Facebook. Таким образом, следующий подход работал очень хорошо для нашего случая и может отличаться для вашего сценария, но может помочь вам в долгосрочной перспективе поиграть с паспортом.
Примечание. Прежде чем следовать приведенному ниже предположению, вы включили предоставление пароля в своем приложении.
Таким образом, мы решили это для нашего проекта на Laravel 5.3 следующим образом:
в oauth_clients преобразуйте поле id в обычное поле, т.е. удалите его как первичный ключ и сделайте тип данных varchar, чтобы мы могли хранить адрес электронной почты как client_ids, поскольку они также уникальны для вашей системы. В случае входа в Facebook мы храним здесь идентификаторы пользователей Facebook, которые также будут уникальными для каждого нашего клиента. Также для других таблиц, таких как: oauth_access_tokens, oauth_auth_codes & oauth_personal_access_clients измените client_id на VARCHAR(255), чтобы он мог хранить адреса электронной почты или идентификаторы пользователей Facebook.
Теперь перейдите к своим моделям и создайте модель для таблицы oauth_clients, чтобы вы могли программно создавать клиента из кода при создании пользователей.
<?php namespace App; use Illuminate\Database\Eloquent\Model; class OauthClient extends Model { protected $table = 'oauth_clients'; }
Затем в вашем файле маршрута api.php добавьте следующий маршрут:
Route::post('/register-user', function (Request $request) { $name = $request->input('name'); $email = $request->input('email'), $password = $request->input('password'), // save new user $user = \App\User::create([ 'name' => $name, 'email' => $email, 'password' => bcrypt($password), ]); // create oauth client $oauth_client = \App\OauthClient::create([ 'user_id' => $user->id, 'id' => $email, 'name' => $name, 'secret' => base64_encode(hash_hmac('sha256',$password, 'secret', true)), 'password_client' => 1, 'personal_access_client' => 0, 'redirect' => '', 'revoked' => 0, ]); return [ 'message' => 'user successfully created.' ]; });
В приведенном выше фрагменте кода вы должны заметить, что для генерации секрета oauth_client вы должны использовать строгую формулу шифрования, которую вам удобно использовать с вашим приложением. Кроме того, используйте ту же технику для генерации секретного ключа в вашем мобильном приложении для соответствующего клиента / пользователя.
Теперь вы можете использовать стандартный POST API, предлагаемый laravel passport, для запроса токена доступа через предоставление пароля с помощью "oauth / token", используя следующие параметры:
grant_type : 'password' client_id : '<email with which the user is registered>' client_secret : '<generate the client secret from the mobile app>' username : '<email with which the user is registered>' password : '<password entered by the user>' scope : '<leave empty as default>'
Вышеприведенный ответ даст вам ответ, если все правильно, примерно так:
{ "token_type": "Bearer", "expires_in": 3155673600, "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjMwZmM0MDk1NWY5YjUwNDViOTUzNDlmZjc2M2ExNDUxOTAxZjc5YTA5YjE4OWM1MjEzOTJlZmNiMDgwOWQzMzQwM2ExZWI4ZmMyODQ1MTE3In0.eyJhdWQiOiJzaHVqYWhtQGdtYWlsLmNvbSIsImp0aSI6IjMwZmM0MDk1NWY5YjUwNDViOTUzNDlmZjc2M2ExNDUxOTAxZjc5YTA5YjE4OWM1MjEzOTJlZmNiMDgwOWQzMzQwM2ExZWI4ZmMyODQ1MTE3IiwiaWF0IjoxNDc4MTQ1NjMyLCJuYmYiOjE0NzgxNDU2MzIsImV4cCI6NDYzMzgxOTIzMiwic3ViIjoiMSIsInNjb3BlcyI6W119.dj3g9b2AdPCK-im5uab-01SP71S7AR96R0FQTKKoaZV7M5ID1pSXDlmZw96o5Bd_Xsy0nUqFsPNRQsLvYaOuHZsP8v9mOVirBXLIBvPcBc6lDRdNXvRidNqeh4JHhJu9a5VzNlJPm3joBYSco4wYzNHs2BPSxXuuD3o63nKRHhuUHB-HwjVxj2GDwzEYXdZmf2ZXOGRJ99DlWGDvWx8xQgMQtd1E9Xk_Rs6Iu8tycjBpKBaC24AKxMI6T8DpelnFmUbMcz-pRsgCWCF_hxv6FpXav3jr1CLhhT58_udBvXjQAXEbtHeB7W_oaMcaqezHdAeOWDcnqREZHsnXHtKt0JpymcTWBkS2cg7sJzy6P9mOGgQ8B4gb8wt44_kHTeWnokk4yPFRZojkHLVZb8YL6hZxLlzgV1jCHUxXoHNe1VKlHArdlV8LAts9pqARZkyBRfwQ8oiTL-2m16FQ_qGg-9vI0Suv7d6_W126afI3LxqDBi8AyqpQzZX1FWmuJLV0QiNM0nzTyokzz7w1ilJP2PxIeUzMRlVaJyA395zq2HjbFEenCkd7bAmTGrgEkyWM6XEq1P7qIC_Ne_pLNAV6DLXUpg9bUWEHhHPXIDYKHS-c3N9fPDt8UVvGI8n0rPMieTN92NsYZ_6OqLNpcm6TrhMNZ9eg5EC0IPySrrv62jE", "refresh_token": "BbwRuDnVfm7tRQk7qSYByFbQKK+shYPDinYA9+q5c/ovIE1xETyWitvq6PU8AHnI5FWb06Nl2BVoBwCHCUmFaeRXQQgYY/i5vIDEQ/TJYFLVPRHDc7CKILF0kMakWKDk7wJdl5J6k5mN38th4pAAZOubiRoZ+2npLC7OSZd5Mq8LCBayzqtyy/QA5MY9ywCgb1PErzrGQhzB3mNhKj7U51ZnYT3nS5nCH7iJkCjaKvd/Hwsx2M6pXnpY45xlDVeTOjZxxaOF/e0+VT2FP2+TZMDRfrSMLBEkpbyX0M/VxunriRJPXTUvl3PW0sVOEa3J7+fbce0XWAKz7PNs3+hcdzD2Av2VHYF7/bJwcDCO77ky0G4JlHjqC0HnnGP2UWI5qR+tCSBga7+M1P3ESjcTCV6G6H+7f8SOSv9FECcJ8J5WUrU+EHrZ95bDtPc9scE4P3OEQaYchlC9GHk2ZoGo5oMJI6YACuRfbGQJNBjdjxvLIrAMrB6DNGDMbH6UZodkpZgQjGVuoCWgFEfLqegHbp34CjwL5ZFJGohV+E87KxedXE6aEseywyjmGLGZwAekjsjNwuxqD2QMb05sg9VkiUPMsvn45K9iCLS5clEKOTwkd+JuWw2IU80pA24aXN64RvOJX5VKMN6CPluJVLdjHeFL55SB7nlDjp15WhoMU1A=" }
Это единственное временное решение до тех пор, пока laravel не поддерживает внешний API для приложений, у которых только мобильный телефон является единственным возможным интерфейсом для создания клиентов и пользователей oAuth.
Надеюсь, это поможет вам! Приветствия.
Поскольку отмеченный ответ был отмечен как правильный, я считаю необходимым отметить некоторые ключевые моменты, с которыми, я думаю, многие согласятся:
Вы почти НИКОГДА не хотите помещать логику серверных процессов такого рода в каталог маршрутов. Особенно при работе над созданием API с намерением запустить его в производство. Это грязный путь и не совсем безопасный.ЕСЛИ НЕ для вещей, которые безопасно обрабатывать в вашем каталоге маршрутов. Например, в меньшем масштабе - базовая логика отправки уведомления (SMS, электронная почта,push,slack) сотрудникам о новом письме / блоге / заметке, опубликованном в качестве примера.
ВСЕГДА пытайтесь использовать и использовать как можно больше возможностей фреймворка, прежде чем пытаться "хакерски" выполнить задачу, которая могла быть выполнена несколько раз раньше.
Убедитесь, что вы проводите надлежащее исследование о том, что уже было сделано. Таким образом, вам будет проще просто сослаться на видео или учебник, в котором показано, как правильно делать то, что кто-то пытается сделать.
При этом хорошей отправной точкой было бы посмотреть следующее видео, которое прекрасно описывает основы правильной настройки того, что вы хотите настроить:
https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/13
Во многих отношениях видеоурок очень хорошо сделан и тщателен от начала до конца. Обязательно ознакомьтесь с различными Grant_Types для OAuth2.0, чтобы у вас было лучшее понимание того, какой конкретный тип вам / вашему приложению нужен, исходя из позиции вашего приложения для использования API:
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
Кроме того, обязательно используйте встроенные функции laravel для входа в систему и регистрации при создании или входе в систему пользователей. Контроллеры создаются для вас, когда вы выполняете в своей консоли следующее:
php artisan make:auth
Кроме того, если паспорт какой-то загадочный, вы всегда можете взять пакет laravel / socialite ( https://github.com/laravel/socialite). Это позволит вам "Войти через (Социальная сеть здесь)". При условии, что по этому маршруту вы тоже стремитесь.
КОНЕЦ ЗАМЕЧАНИЯ: Часть, которую я видел в вашем вопросе, которая больше всего выделялась, была о том, как человек будет регистрироваться, но не будет входить через Facebook. Вместо этого будет иметь токен доступа для доступа к различным конечным точкам API. Поэтому, если я правильно понимаю, что вы говорите, вы намереваетесь использовать данные пользователя из Facebook при возврате данных, пользователь считается вошедшим в систему и должен получить маркер доступа. ТАК:
Используйте socialite, чтобы отправить запрос на вход в систему через Facebook. Это позволит получить данные пользователя и немного использовать процесс аутентификации Facebook.
Когда запрос возвращается с пользовательскими данными внутри тела, пропустите его, чтобы убедиться, что данные есть (просто оператор if должен подойти). Поскольку Facebook уже проверил подлинность этого пользователя и отправленные учетные данные, вы должны быть готовы.
Вы можете либо запустить внутренний прокси-сервер в вашем контроллере входа в систему (что является более чистым и безопасным способом сделать это), либо вы можете выпустить JWT (что описано в последних 5 минутах видео, опубликованного в этом ответе выше).
Ниже приведен пример кода, с которого можно начать.
App \ Http \ Контроллеры \Auth\LoginController.php
class LoginController extends Controller { // ... protected function authenticateClient(Request $request) { $credentials = $this->credentials($request); $data = $request->all(); $user = User::where('email', $credentials['email'])->first(); $request->request->add([ 'grant_type' => $data['grant_type'], 'client_id' => $data['client_id'], 'client_secret' => $data['client_secret'], 'username' => $credentials['email'], 'password' => $credentials['password'], 'scope' => null, ]); $proxy = Request::create( 'oauth/token', 'POST' ); return Route::dispatch($proxy); } protected function authenticated(Request $request, $user) { return $this->authenticateClient($request); } protected function sendLoginResponse(Request $request) { $request->session()->regenerate(); $this->clearLoginAttempts($request); return $this->authenticated($request, $this->guard()->user()); } public function login(Request $request) { if ($this->guard('api')->attempt($credentials, $request->has('remember'))) { return $this->sendLoginResponse($request); } } }
Приведенный выше код используется В СЛУЧАЕ, когда вы собираетесь использовать тип " Предоставление пароля " для аутентификации клиентов по паспорту. Тем не менее, я бы серьезно посмотрел обучающее видео, прежде чем бросать оружие на что-либо. Это поможет вам с тем, как использовать laravel 5.3 с паспортом.