() translation by (you can also view the original English article)
En este artículo, vamos a explorar cómo puede configurar un servidor OAuth2 completamente desarrollado en Laravel utilizando la biblioteca Laravel Passport. Revisaremos las configuraciones de servidor necesarias junto con un ejemplo del mundo real para demostrar cómo puede consumir las API de OAuth2.
Supongo que está familiarizado con los conceptos básicos de OAuth2 y el flujo, ya que los discutiremos en el contexto de Laravel. De hecho, la biblioteca Laravel Passport hace que sea muy fácil configurar rápidamente un servidor OAuth2 en su aplicación. Por lo tanto, otras aplicaciones de terceros pueden consumir API proporcionadas por su aplicación.
En la primera mitad del artículo, instalaremos y configuraremos las bibliotecas necesarias, y la segunda parte explicará cómo configurar recursos de demostración en su aplicación y consumirlos desde aplicaciones de terceros.
Configuraciones del servidor
En esta sección, vamos a instalar las dependencias necesarias para que la biblioteca de Passport funcione con Laravel. Después de la instalación, hay un poco de configuración que tendremos que pasar para que Laravel pueda detectar la biblioteca de Passport.
Avancemos e instalemos la biblioteca de Passport usando composer
1 |
$composer require laravel/passport
|
Eso es más o menos en lo que se refiere a la instalación de la biblioteca Passport. Ahora asegurémonos de que Laravel lo sepa.
Al
trabajar con Laravel, probablemente conozca el concepto de un proveedor
de servicios que le permite configurar servicios en su aplicación. Por
lo tanto, siempre que quiera habilitar un nuevo servicio en su
aplicación Laravel, solo necesita agregar una entrada de proveedor de
servicio asociado en config / app.php.
Si aún no conoce a los proveedores de servicios de Laravel, le recomiendo encarecidamente que se haga un favor y lea este artículo introductorio que explica los conceptos básicos de los proveedores de servicios en Laravel.
En nuestro caso,
solo tenemos que agregar el proveedor PassportServiceProvider
a la
lista de proveedores de servicios en config / app.php
como se muestra en
el siguiente fragmento.
1 |
...
|
2 |
...
|
3 |
'providers' => [ |
4 |
|
5 |
/*
|
6 |
* Laravel Framework Service Providers...
|
7 |
*/
|
8 |
Illuminate\Auth\AuthServiceProvider::class, |
9 |
Illuminate\Broadcasting\BroadcastServiceProvider::class, |
10 |
Illuminate\Bus\BusServiceProvider::class, |
11 |
Illuminate\Cache\CacheServiceProvider::class, |
12 |
Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, |
13 |
Illuminate\Cookie\CookieServiceProvider::class, |
14 |
Illuminate\Database\DatabaseServiceProvider::class, |
15 |
Illuminate\Encryption\EncryptionServiceProvider::class, |
16 |
Illuminate\Filesystem\FilesystemServiceProvider::class, |
17 |
Illuminate\Foundation\Providers\FoundationServiceProvider::class, |
18 |
Illuminate\Hashing\HashServiceProvider::class, |
19 |
Illuminate\Mail\MailServiceProvider::class, |
20 |
Illuminate\Notifications\NotificationServiceProvider::class, |
21 |
Illuminate\Pagination\PaginationServiceProvider::class, |
22 |
Illuminate\Pipeline\PipelineServiceProvider::class, |
23 |
Illuminate\Queue\QueueServiceProvider::class, |
24 |
Illuminate\Redis\RedisServiceProvider::class, |
25 |
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, |
26 |
Illuminate\Session\SessionServiceProvider::class, |
27 |
Illuminate\Translation\TranslationServiceProvider::class, |
28 |
Illuminate\Validation\ValidationServiceProvider::class, |
29 |
Illuminate\View\ViewServiceProvider::class, |
30 |
|
31 |
/*
|
32 |
* Package Service Providers...
|
33 |
*/
|
34 |
Laravel\Tinker\TinkerServiceProvider::class, |
35 |
|
36 |
/*
|
37 |
* Application Service Providers...
|
38 |
*/
|
39 |
App\Providers\AppServiceProvider::class, |
40 |
App\Providers\AuthServiceProvider::class, |
41 |
App\Providers\BroadcastServiceProvider::class, |
42 |
App\Providers\EventServiceProvider::class, |
43 |
App\Providers\RouteServiceProvider::class, |
44 |
Laravel\Passport\PassportServiceProvider::class, |
45 |
],
|
46 |
...
|
47 |
...
|
A continuación,
debemos ejecutar el comando migrate
artesanal, que crea las tablas
necesarias en una base de datos para la biblioteca Passport.
1 |
$php artisan migrate
|
Para ser precisos, crea siguiendo las tablas en la base de datos.
1 |
oauth_access_tokens
|
2 |
oauth_auth_codes
|
3 |
oauth_clients
|
4 |
oauth_personal_access_clients
|
5 |
oauth_refresh_tokens
|
A continuación, necesitamos generar un par de claves públicas y privadas que la biblioteca de Passport utilizará para el cifrado. Como era de esperar, la biblioteca Passport proporciona un comando artesanal para crearlo fácilmente.
1 |
$php artisan passport:install
|
Eso debería haber creado las claves en storage / oauth-public.key
y storage / oauth-private.key
. También crea algunas credenciales de demostración de cliente que veremos más adelante.
Avanzando, vamos a oauthificar la clase de modelo de usuario existente que Laravel usa para la autenticación. Para hacer eso, necesitamos agregar el rasgo HasApiTokens
a la clase de modelo de User
. Hagamos eso como se muestra en el siguiente fragmento.
1 |
<?php
|
2 |
|
3 |
namespace App; |
4 |
|
5 |
use Illuminate\Notifications\Notifiable; |
6 |
use Illuminate\Foundation\Auth\User as Authenticatable; |
7 |
use Laravel\Passport\HasApiTokens; |
8 |
|
9 |
class User extends Authenticatable |
10 |
{
|
11 |
use HasApiTokens; |
12 |
|
13 |
/**
|
14 |
* The attributes that are mass assignable.
|
15 |
*
|
16 |
* @var array
|
17 |
*/
|
18 |
protected $fillable = [ |
19 |
'name', 'email', 'password', |
20 |
];
|
21 |
|
22 |
/**
|
23 |
* The attributes that should be hidden for arrays.
|
24 |
*
|
25 |
* @var array
|
26 |
*/
|
27 |
protected $hidden = [ |
28 |
'password', 'remember_token', |
29 |
];
|
30 |
}
|
El rasgo
HasApiTokens
contiene métodos auxiliares que se utilizan para validar
los tokens en la solicitud y verificar el alcance de los recursos
solicitados en el contexto del usuario autenticado actualmente.
Además, tenemos que registrar las rutas provistas por la biblioteca Passport con nuestra aplicación Laravel. Estas rutas se usarán para operaciones estándar de OAuth2, como autorización, solicitud de tokens de acceso y similares.
En el método de
arranque de la app / Providers / AuthServiceProvider.php
,
registremos las rutas de la biblioteca de Passport.
1 |
...
|
2 |
...
|
3 |
/**
|
4 |
* Register any authentication / authorization services.
|
5 |
*
|
6 |
* @return void
|
7 |
*/
|
8 |
public function boot() |
9 |
{
|
10 |
$this->registerPolicies(); |
11 |
|
12 |
Passport::routes(); |
13 |
}
|
14 |
...
|
15 |
...
|
Por último, pero
no por ello menos importante, debemos cambiar el controlador de la API
de token a pasaporte en el archivo config / auth.php
, ya que vamos a
utilizar la biblioteca de Passport para la autenticación API.
1 |
'guards' => [ |
2 |
'web' => [ |
3 |
'driver' => 'session', |
4 |
'provider' => 'users', |
5 |
],
|
6 |
|
7 |
'api' => [ |
8 |
'driver' => 'passport', |
9 |
'provider' => 'users', |
10 |
],
|
11 |
],
|
Hasta ahora, hemos hecho todo lo que se requiere en lo que respecta a la configuración del servidor OAuth2.
Configure los recursos de demostración
En la sección anterior, hicimos todo el trabajo para configurar el servidor de autenticación OAuth2 en nuestra aplicación. En esta sección, configuraremos un recurso de demostración que podría solicitarse sobre la llamada API.
Intentaremos mantener las cosas simples. Nuestro
recurso de demostración devuelve la información del usuario siempre que
haya un parámetro de uid
válido presente en la solicitud GET
.
Vamos a crear un archivo de controlador app / Http / Controllers / UserController.php
con los siguientes contenidos.
1 |
<?php
|
2 |
namespace App\Http\Controllers; |
3 |
|
4 |
use App\Http\Controllers\Controller; |
5 |
use Illuminate\Http\Request; |
6 |
use App\User; |
7 |
|
8 |
class UserController extends Controller |
9 |
{
|
10 |
public function get(Request $request) |
11 |
{
|
12 |
$user_id = $request->get("uid", 0); |
13 |
$user = User::find($user_id); |
14 |
return $user; |
15 |
}
|
16 |
}
|
Como es habitual, también debe agregar una ruta asociada, que debe agregar en el archivo routes / web.php
. Pero de lo que estamos hablando es de la ruta API, y por lo tanto, necesita un tratamiento especial.
Las rutas API se definen en el archivo routes / api.php
. Entonces, continuemos y agreguemos nuestra ruta API personalizada como se muestra en el siguiente fragmento.
1 |
<?php
|
2 |
|
3 |
use Illuminate\Http\Request; |
4 |
|
5 |
/*
|
6 |
|--------------------------------------------------------------------------
|
7 |
| API Routes
|
8 |
|--------------------------------------------------------------------------
|
9 |
|
|
10 |
| Here is where you can register API routes for your application. These
|
11 |
| routes are loaded by the RouteServiceProvider within a group which
|
12 |
| is assigned the "api" middleware group. Enjoy building your API!
|
13 |
|
|
14 |
*/
|
15 |
|
16 |
Route::middleware('auth:api')->get('/user', function (Request $request) { |
17 |
return $request->user(); |
18 |
});
|
19 |
|
20 |
// custom API route
|
21 |
Route::middleware('auth:api')->get('/user/get', 'UserController@get'); |
Aunque
lo hemos definido como / user / get
, la ruta API efectiva es / api /
user / get
, y eso es lo que debe usar cuando solicita un recurso sobre
esa ruta. El prefijo api
es manejado automáticamente por Laravel, ¡y no tienes que preocuparte por eso!
En la siguiente y última sección, analizaremos cómo puede crear credenciales de clientes y consumir la API de OAuth2.
Cómo consumir las API de OAuth2
Ahora que hemos configurado el servidor OAuth2 en nuestra aplicación, cualquier tercero puede conectarse a nuestro servidor con OAuth y consumir las API disponibles en nuestra aplicación.
En primer lugar, las aplicaciones de terceros deben registrarse en nuestra aplicación para poder consumir API. En otras palabras, se consideran aplicaciones cliente y recibirán una identificación de cliente y un secreto de cliente al registrarse.
La biblioteca Passport proporciona un comando artesanal para crear cuentas de clientes sin mucha molestia. Avancemos y creemos una cuenta de cliente demo.
1 |
$php artisan passport:client
|
2 |
Which user ID should the client be assigned to?: |
3 |
> 1
|
4 |
|
5 |
What should we name the client?: |
6 |
> Demo OAuth2 Client Account
|
7 |
|
8 |
Where should we redirect the request after authorization? [https://localhost/auth/callback]:
|
9 |
> http://localhost/oauth2_client/callback.php
|
10 |
|
11 |
New client created successfully. |
12 |
Client ID: 1 |
13 |
Client secret: zMm0tQ9Cp7LbjK3QTgPy1pssoT1X0u7sg0YWUW01 |
Cuando ejecuta el comando passport:client
artesanal: , le hace algunas preguntas antes de crear la cuenta del cliente. De ellos, hay uno importante que le pide la callback URL
La callback URL
es aquella en la que los usuarios serán
redirigidos al extremo de terceros después de la autorización. Y ahí es donde se enviará el código de autorización que se supone que se usará a cambio del token de acceso. Estamos a punto de crear ese archivo en un momento.
Ahora, estamos listos para probar las API de OAuth2 en la aplicación Laravel.
Para fines de demostración, crearé el directorio oauth2_client
debajo de la raíz del documento en primer lugar. Idealmente, estos archivos se ubicarán en el extremo de terceros que desea consumir API en nuestra aplicación Laravel.
Vamos a crear el archivo oauth2_client / auth_redirection.php
con los siguientes contenidos.
1 |
<?php
|
2 |
$query = http_build_query(array( |
3 |
'client_id' => '1', |
4 |
'redirect_uri' => 'http://localhost/oauth2_client/callback.php', |
5 |
'response_type' => 'code', |
6 |
'scope' => '', |
7 |
));
|
8 |
|
9 |
header('Location: http://your-laravel-site-url/oauth/authorize?'.$query); |
Asegúrese de
cambiar los parámetros client_id
y redirect_uri
para que reflejen su
propia configuración, las que utilizó al crear la cuenta del cliente de
demostración.
A continuación, creemos el archivo oauth2_client / callback.php
con los siguientes contenidos.
1 |
<?php
|
2 |
// check if the response includes authorization_code
|
3 |
if (isset($_REQUEST['code']) && $_REQUEST['code']) |
4 |
{
|
5 |
$ch = curl_init(); |
6 |
$url = 'http://your-laravel-site-url/oauth/token'; |
7 |
|
8 |
$params = array( |
9 |
'grant_type' => 'authorization_code', |
10 |
'client_id' => '1', |
11 |
'client_secret' => 'zMm0tQ9Cp7LbjK3QTgPy1pssoT1X0u7sg0YWUW01', |
12 |
'redirect_uri' => 'http://localhost/oauth2_client/callback.php', |
13 |
'code' => $_REQUEST['code'] |
14 |
);
|
15 |
|
16 |
curl_setopt($ch,CURLOPT_URL, $url); |
17 |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
18 |
|
19 |
$params_string = ''; |
20 |
|
21 |
if (is_array($params) && count($params)) |
22 |
{
|
23 |
foreach($params as $key=>$value) { |
24 |
$params_string .= $key.'='.$value.'&'; |
25 |
}
|
26 |
|
27 |
rtrim($params_string, '&'); |
28 |
|
29 |
curl_setopt($ch,CURLOPT_POST, count($params)); |
30 |
curl_setopt($ch,CURLOPT_POSTFIELDS, $params_string); |
31 |
}
|
32 |
|
33 |
$result = curl_exec($ch); |
34 |
curl_close($ch); |
35 |
$response = json_decode($result); |
36 |
|
37 |
// check if the response includes access_token
|
38 |
if (isset($response->access_token) && $response->access_token) |
39 |
{
|
40 |
// you would like to store the access_token in the session though...
|
41 |
$access_token = $response->access_token; |
42 |
|
43 |
// use above token to make further api calls in this session or until the access token expires
|
44 |
$ch = curl_init(); |
45 |
$url = 'http://your-laravel-site-url/api/user/get'; |
46 |
$header = array( |
47 |
'Authorization: Bearer '. $access_token |
48 |
);
|
49 |
$query = http_build_query(array('uid' => '1')); |
50 |
|
51 |
curl_setopt($ch,CURLOPT_URL, $url . '?' . $query); |
52 |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
53 |
curl_setopt($ch, CURLOPT_HTTPHEADER, $header); |
54 |
$result = curl_exec($ch); |
55 |
curl_close($ch); |
56 |
$response = json_decode($result); |
57 |
var_dump($result); |
58 |
}
|
59 |
else
|
60 |
{
|
61 |
// for some reason, the access_token was not available
|
62 |
// debugging goes here
|
63 |
}
|
64 |
}
|
De nuevo, asegúrese de ajustar las URL y las credenciales del cliente de acuerdo con su configuración en el archivo anterior.
Cómo funciona en conjunto
En esta sección, lo probaremos por completo desde la perspectiva de un usuario final. Como usuario final, hay dos aplicaciones frente a usted:
- El primero es la aplicación Laravel con la que ya tiene una cuenta. Contiene su información que podría compartir con otras aplicaciones de terceros.
- El
segundo es la aplicación cliente de demostración demo,
auth_redirection.php
ycallback.php
, que quiere obtener su información de la aplicación Laravel utilizando la API OAuth.
El flujo comienza desde la aplicación cliente de terceros. Continúa y abre la URL http: //localhost/oauth2_client/auth_redirection.php en tu navegador, y eso debería redireccionarte a la aplicación Laravel. Si aún no ha iniciado sesión en la aplicación Laravel, la aplicación le pedirá que lo haga en primer lugar.
Una vez que el usuario inicia sesión, la aplicación muestra la página de autorización.
Si
el usuario autoriza esa solicitud, el usuario será redirigido a la
aplicación de cliente de terceros en http:
//localhost/oauth2_client/callback.php junto con el code
como el
parámetro GET
que contiene el código de autorización.
Una vez que la aplicación de terceros recibe el código de autorización, puede intercambiar ese código con la aplicación Laravel para obtener el token de acceso. Y eso es exactamente lo que ha hecho en el siguiente fragmento del archivo oauth2_client / callback.php
.
1 |
$ch = curl_init(); |
2 |
$url = 'http://your-laravel-site-url/oauth/token'; |
3 |
|
4 |
$params = array( |
5 |
'grant_type' => 'authorization_code', |
6 |
'client_id' => '1', |
7 |
'client_secret' => 'zMm0tQ9Cp7LbjK3QTgPy1pssoT1X0u7sg0YWUW01', |
8 |
'redirect_uri' => 'http://localhost/oauth2_client/callback.php', |
9 |
'code' => $_REQUEST['code'] |
10 |
);
|
11 |
|
12 |
curl_setopt($ch,CURLOPT_URL, $url); |
13 |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
14 |
|
15 |
$params_string = ''; |
16 |
|
17 |
if (is_array($params) && count($params)) |
18 |
{
|
19 |
foreach($params as $key=>$value) { |
20 |
$params_string .= $key.'='.$value.'&'; |
21 |
}
|
22 |
|
23 |
rtrim($params_string, '&'); |
24 |
|
25 |
curl_setopt($ch,CURLOPT_POST, count($params)); |
26 |
curl_setopt($ch,CURLOPT_POSTFIELDS, $params_string); |
27 |
}
|
28 |
|
29 |
$result = curl_exec($ch); |
30 |
curl_close($ch); |
31 |
$response = json_decode($result); |
A continuación, la aplicación de terceros comprueba la respuesta de la solicitud CURL para ver si contiene un token de acceso válido en primer lugar.
Tan pronto como la aplicación de terceros obtenga el token de acceso, podría usar ese token para realizar más llamadas a la API para solicitar recursos según sea necesario desde la aplicación Laravel. Por supuesto, el token de acceso debe pasarse en cada solicitud que solicite recursos de la aplicación Laravel.
Hemos tratado de imitar el caso de uso en el sentido de que la aplicación de terceros quiere acceder a la información del usuario desde la aplicación Laravel. Y ya hemos creado un punto final API, http: // su-laravel-site-url / api / user / get, en la aplicación Laravel que lo facilita.
1 |
// check if the response includes access_token
|
2 |
if (isset($response->access_token) && $response->access_token) |
3 |
{
|
4 |
// you would like to store the access_token in the session though...
|
5 |
$access_token = $response->access_token; |
6 |
|
7 |
// use above token to make further api calls in this session or until the access token expires
|
8 |
$ch = curl_init(); |
9 |
$url = 'http://your-laravel-site-url/api/user/get'; |
10 |
$header = array( |
11 |
'Authorization: Bearer '. $access_token |
12 |
);
|
13 |
$query = http_build_query(array('uid' => '1')); |
14 |
|
15 |
curl_setopt($ch,CURLOPT_URL, $url . '?' . $query); |
16 |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
17 |
curl_setopt($ch, CURLOPT_HTTPHEADER, $header); |
18 |
$result = curl_exec($ch); |
19 |
curl_close($ch); |
20 |
$response = json_decode($result); |
21 |
var_dump($result); |
22 |
}
|
Así que ese es el flujo completo de cómo se supone que debes consumir las API de OAuth2 en Laravel.
Y con eso, hemos llegado al final de este artículo.
Conclusión
Hoy exploramos la biblioteca de Passport en Laravel, lo que nos permite configurar un servidor OAuth2 en una aplicación muy fácilmente.
Para
aquellos de ustedes que recién están empezando con Laravel o buscando ampliar su conocimiento, sitio o aplicación con extensiones, tenemos una variedad de cosas que pueden estudiar en Envato Market.
¡No dude en compartir sus pensamientos y consultas utilizando el feed a continuación!