Статьи

Настройка сервера OAuth2 с использованием паспорта в Laravel

В этой статье мы рассмотрим, как вы можете настроить полноценный сервер OAuth2 в Laravel, используя библиотеку Laravel Passport. Мы рассмотрим необходимые конфигурации серверов вместе с реальным примером, чтобы продемонстрировать, как вы можете использовать API-интерфейсы OAuth2.

Я предполагаю, что вы знакомы с базовыми концепциями OAuth2 и процессом, который мы собираемся обсудить в контексте Laravel. Фактически, библиотека Laravel Passport позволяет довольно быстро настроить сервер OAuth2 в вашем приложении. Таким образом, другие сторонние приложения могут использовать API, предоставленные вашим приложением.

В первой половине статьи мы будем устанавливать и настраивать необходимые библиотеки, а во второй половине рассказывается, как настроить демонстрационные ресурсы в вашем приложении и использовать их из сторонних приложений.

В этом разделе мы собираемся установить зависимости, необходимые для работы библиотеки Passport с Laravel. После установки нам нужно будет выполнить довольно много настроек, чтобы Laravel мог обнаружить библиотеку Passport.

Давайте продолжим и установим библиотеку Passport с помощью composer.

1
$composer require laravel/passport

В значительной степени это касается установки библиотеки Passport. Теперь давайте удостоверимся, что Ларавел знает об этом.

Работая с Laravel, вы, вероятно, знаете о концепции поставщика услуг, который позволяет вам настраивать службы в вашем приложении. Таким образом, всякий раз, когда вы хотите включить новую службу в своем приложении Laravel, вам просто нужно добавить соответствующую запись поставщика услуг в config/app.php .

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

В нашем случае нам просто нужно добавить поставщика PassportServiceProvider в список поставщиков услуг в config/app.php как показано в следующем фрагменте.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
‘providers’ => [
 
        /*
         * Laravel Framework Service Providers…
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        Illuminate\Filesystem\FilesystemServiceProvider::class,
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
        Illuminate\Hashing\HashServiceProvider::class,
        Illuminate\Mail\MailServiceProvider::class,
        Illuminate\Notifications\NotificationServiceProvider::class,
        Illuminate\Pagination\PaginationServiceProvider::class,
        Illuminate\Pipeline\PipelineServiceProvider::class,
        Illuminate\Queue\QueueServiceProvider::class,
        Illuminate\Redis\RedisServiceProvider::class,
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
        Illuminate\Session\SessionServiceProvider::class,
        Illuminate\Translation\TranslationServiceProvider::class,
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,
 
        /*
         * Package Service Providers…
         */
        Laravel\Tinker\TinkerServiceProvider::class,
 
        /*
         * Application Service Providers…
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,
        Laravel\Passport\PassportServiceProvider::class,
],

Далее нам нужно выполнить команду migrate artisan, которая создает необходимые таблицы в базе данных для библиотеки Passport.

1
$php artisan migrate

Чтобы быть точным, он создает следующие таблицы в базе данных.

1
2
3
4
5
oauth_access_tokens
oauth_auth_codes
oauth_clients
oauth_personal_access_clients
oauth_refresh_tokens

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

1
$php artisan passport:install

Это должно было создать ключи в storage/oauth-public.key и storage/oauth-private.key . Он также создает некоторые учетные данные демо-клиента, к которым мы вернемся позже.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
 
namespace App;
 
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;
 
class User extends Authenticatable
{
    use HasApiTokens;
 
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        ‘name’, ’email’, ‘password’,
    ];
 
    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        ‘password’, ‘remember_token’,
    ];
}

Черта HasApiTokens содержит вспомогательные методы, которые используются для проверки токенов в запросе и проверки объема ресурсов, запрашиваемых в контексте аутентифицированного в данный момент пользователя.

Кроме того, нам нужно зарегистрировать маршруты, предоставляемые библиотекой Passport, в нашем приложении Laravel. Эти маршруты будут использоваться для стандартных операций OAuth2, таких как авторизация, запрос маркеров доступа и тому подобное.

В методе загрузки файла app/Providers/AuthServiceProvider.php зарегистрируем маршруты библиотеки Passport.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
/**
  * Register any authentication / authorization services.
  *
  * @return void
  */
public function boot()
{
    $this->registerPolicies();
     
    Passport::routes();
}

И последнее, но не менее важное: нам нужно изменить драйвер api с токена на паспорт в файле config/auth.php , так как мы собираемся использовать библиотеку Passport для аутентификации API.

01
02
03
04
05
06
07
08
09
10
11
‘guards’ => [
    ‘web’ => [
        ‘driver’ => ‘session’,
        ‘provider’ => ‘users’,
    ],
 
    ‘api’ => [
        ‘driver’ => ‘passport’,
        ‘provider’ => ‘users’,
    ],
],

До сих пор мы сделали все, что требуется для конфигурации сервера OAuth2.

В предыдущем разделе мы проделали всю тяжелую работу по настройке сервера аутентификации OAuth2 в нашем приложении. В этом разделе мы настроим демонстрационный ресурс, который можно запрашивать через вызов API.

Мы постараемся сделать вещи простыми. Наш демонстрационный ресурс возвращает информацию о пользователе при условии, что в GET запросе присутствует допустимый параметр uid .

Давайте создадим файл контроллера app/Http/Controllers/UserController.php со следующим содержимым.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<?php
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
 
class UserController extends Controller
{
    public function get(Request $request)
    {
      $user_id = $request->get(«uid», 0);
      $user = User::find($user_id);
      return $user;
    }
}

Как обычно, вам также необходимо добавить связанный маршрут, который вы должны добавить в файл routes/web.php . Но мы говорим о маршруте API, и поэтому он требует особого подхода.

Маршруты API определены в файле routes/api.php . Итак, давайте продолжим и добавим наш собственный маршрут API, как показано в следующем фрагменте.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
<?php
 
use Illuminate\Http\Request;
 
/*
|—————————————————————————
|
|—————————————————————————
|
|
|
|
|
*/
 
Route::middleware(‘auth:api’)->get(‘/user’, function (Request $request) {
    return $request->user();
});
 
// custom API route
Route::middleware(‘auth:api’)->get(‘/user/get’, ‘UserController@get’);

Хотя мы определили его как /user/get , эффективный маршрут API — это /api/user/get , и это то, что вы должны использовать при запросе ресурса по этому маршруту. Префикс api автоматически обрабатывается Laravel, и вам не нужно об этом беспокоиться!

В следующем и последнем разделе мы обсудим, как вы можете создавать учетные данные клиента и использовать OAuth2 API.

Теперь, когда мы настроили сервер OAuth2 в нашем приложении, любая третья сторона может подключиться к нашему серверу с помощью OAuth и использовать API, доступные в нашем приложении.

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

Библиотека Passport предоставляет команду для создания учетных записей клиентов без особых хлопот. Давайте продолжим и создадим демо-счет клиента.

01
02
03
04
05
06
07
08
09
10
11
12
13
$php artisan passport:client
Which user ID should the client be assigned to?:
 > 1
 
 What should we name the client?:
 > Demo OAuth2 Client Account
 
 Where should we redirect the request after authorization?
 > http://localhost/oauth2_client/callback.php
 
New client created successfully.
Client ID: 1
Client secret: zMm0tQ9Cp7LbjK3QTgPy1pssoT1X0u7sg0YWUW01

Когда вы запускаете команду artisan passport:client , она задает вам несколько вопросов перед созданием учетной записи клиента. Из них есть важный, который запрашивает у вас callback URL .

callback URL — это callback URL , по которому пользователи будут перенаправлены обратно на сторонний сервер после авторизации. И именно здесь будет отправлен код авторизации, который предполагается использовать в обмен на токен доступа. Мы собираемся создать этот файл в ближайшее время.

Теперь мы готовы протестировать API OAuth2 в приложении Laravel.

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

Давайте создадим файл oauth2_client/auth_redirection.php со следующим содержимым.

1
2
3
4
5
6
7
8
9
<?php
$query = http_build_query(array(
    ‘client_id’ => ‘1’,
    ‘redirect_uri’ => ‘http://localhost/oauth2_client/callback.php’,
    ‘response_type’ => ‘code’,
    ‘scope’ => »,
));
 
header(‘Location: http://your-laravel-site-url/oauth/authorize?’.$query);

Обязательно измените параметры client_id и redirect_uri чтобы они отражали ваши собственные настройки — те, которые вы использовали при создании учетной записи демо-клиента.

Далее, давайте создадим файл oauth2_client/callback.php со следующим содержимым.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?php
// check if the response includes authorization_code
if (isset($_REQUEST[‘code’]) && $_REQUEST[‘code’])
{
    $ch = curl_init();
    $url = ‘http://your-laravel-site-url/oauth/token’;
 
    $params = array(
        ‘grant_type’ => ‘authorization_code’,
        ‘client_id’ => ‘1’,
        ‘client_secret’ => ‘zMm0tQ9Cp7LbjK3QTgPy1pssoT1X0u7sg0YWUW01’,
        ‘redirect_uri’ => ‘http://localhost/oauth2_client/callback.php’,
        ‘code’ => $_REQUEST[‘code’]
    );
 
    curl_setopt($ch,CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 
    $params_string = »;
 
    if (is_array($params) && count($params))
    {
        foreach($params as $key=>$value) {
            $params_string .= $key.’=’.$value.’&’;
        }
 
        rtrim($params_string, ‘&’);
 
        curl_setopt($ch,CURLOPT_POST, count($params));
        curl_setopt($ch,CURLOPT_POSTFIELDS, $params_string);
    }
 
    $result = curl_exec($ch);
    curl_close($ch);
    $response = json_decode($result);
     
    // check if the response includes access_token
    if (isset($response->access_token) && $response->access_token)
    {
        // you would like to store the access_token in the session though…
        $access_token = $response->access_token;
 
        // use above token to make further api calls in this session or until the access token expires
        $ch = curl_init();
        $url = ‘http://your-laravel-site-url/api/user/get’;
        $header = array(
        ‘Authorization: Bearer ‘.
        );
        $query = http_build_query(array(‘uid’ => ‘1’));
 
        curl_setopt($ch,CURLOPT_URL, $url . ‘?’ . $query);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        $result = curl_exec($ch);
        curl_close($ch);
        $response = json_decode($result);
        var_dump($result);
    }
    else
    {
        // for some reason, the access_token was not available
        // debugging goes here
    }
}

Опять же, не забудьте настроить URL-адреса и учетные данные клиента в соответствии с настройками в приведенном выше файле.

В этом разделе мы проверим его полностью с точки зрения конечного пользователя. Как конечный пользователь, перед вами есть два приложения:

  1. Первое — это приложение Laravel, с которым у вас уже есть аккаунт. Он содержит вашу информацию, которую вы могли бы поделиться с другими сторонними приложениями.
  2. Второе — это демонстрационное стороннее клиентское приложение, auth_redirection.php и callback.php , которое хочет получить вашу информацию из приложения Laravel с помощью OAuth API.

Поток запускается из стороннего клиентского приложения. Идите вперед и откройте http: //localhost/oauth2_client/auth_redirection.php URL в вашем браузере, и это должно перенаправить вас в приложение Laravel. Если вы еще не вошли в приложение Laravel, приложение сначала попросит вас сделать это.

Как только пользователь вошел в систему, приложение отобразит страницу авторизации.

Если пользователь авторизует этот запрос, он будет перенаправлен обратно в стороннее клиентское приложение по адресу http: //localhost/oauth2_client/callback.php вместе с code в качестве параметра GET который содержит код авторизации.

Как только стороннее приложение получит код авторизации, оно может обменяться этим кодом с приложением Laravel, чтобы получить токен доступа. И это именно то, что он сделал в следующем фрагменте файла oauth2_client/callback.php .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$ch = curl_init();
$url = ‘http://your-laravel-site-url/oauth/token’;
 
$params = array(
    ‘grant_type’ => ‘authorization_code’,
    ‘client_id’ => ‘1’,
    ‘client_secret’ => ‘zMm0tQ9Cp7LbjK3QTgPy1pssoT1X0u7sg0YWUW01’,
    ‘redirect_uri’ => ‘http://localhost/oauth2_client/callback.php’,
    ‘code’ => $_REQUEST[‘code’]
);
 
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 
$params_string = »;
 
if (is_array($params) && count($params))
{
    foreach($params as $key=>$value) {
        $params_string .= $key.’=’.$value.’&’;
    }
 
    rtrim($params_string, ‘&’);
 
    curl_setopt($ch,CURLOPT_POST, count($params));
    curl_setopt($ch,CURLOPT_POSTFIELDS, $params_string);
}
 
$result = curl_exec($ch);
curl_close($ch);
$response = json_decode($result);

Затем стороннее приложение проверяет ответ на запрос CURL, чтобы определить, содержит ли он в первую очередь действительный токен доступа.

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

Мы попытались имитировать сценарий использования, когда стороннее приложение хочет получить доступ к пользовательской информации из приложения Laravel. И мы уже создали конечную точку API, http: // your-laravel-site-url / api / user / get , в приложении Laravel, которое облегчает это.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
// check if the response includes access_token
if (isset($response->access_token) && $response->access_token)
{
    // you would like to store the access_token in the session though…
    $access_token = $response->access_token;
 
    // use above token to make further api calls in this session or until the access token expires
    $ch = curl_init();
    $url = ‘http://your-laravel-site-url/api/user/get’;
    $header = array(
    ‘Authorization: Bearer ‘.
    );
    $query = http_build_query(array(‘uid’ => ‘1’));
 
    curl_setopt($ch,CURLOPT_URL, $url . ‘?’ . $query);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    $result = curl_exec($ch);
    curl_close($ch);
    $response = json_decode($result);
    var_dump($result);
}

Итак, это полный поток того, как вы должны использовать API OAuth2 в Laravel.

И с этим мы достигли конца этой статьи.

Сегодня мы исследовали библиотеку Passport в Laravel, которая позволяет нам очень легко настроить сервер OAuth2 в приложении.

Для тех из вас, кто только начинает работать с Laravel или хочет расширить свои знания, сайт или приложение с помощью расширений, у нас есть множество вещей, которые вы можете изучить на Envato Market .

Не стесняйтесь поделиться своими мыслями и вопросами, используя канал ниже!