在本文中,我们将探索如何使用 Laravel passport 库在 Laravel 中设置一个成熟的 oauth2 服务器。我们将介绍必要的服务器配置以及一个真实示例,以演示如何使用 oauth2 api。
我假设你熟悉基本的 OAuth2 概念和流程,因为我们将在 Laravel 的上下文中讨论它们。事实上,Laravel Passport库可以很容易地在你的应用程序中快速设置 OAuth2 服务器。因此,其他第三方应用程序能够使用您的应用程序提供的 API。
在本文的前半部分,我们将安装和配置必要的库,后半部分将介绍如何在您的应用程序中设置演示资源并从第三方应用程序中使用它们。
服务器配置
在本节中,我们将安装所需的依赖项,以使 Passport 库与 Laravel 一起使用。安装后,我们需要进行相当多的配置,以便 Laravel 可以检测 Passport 库。
安装 Laravel Passport 库
让我们继续使用 composer 安装 Passport 库。
$composer require laravel/passport
就 Laravel Passport 库安装而言,差不多就是这样。现在让我们确保 Laravel 知道它。
启用护照服务
使用 Laravel,您可能知道服务提供者的概念,它允许您在应用程序中配置服务。因此,每当您想在 Laravel 应用程序中启用新服务时,您只需在config/app.php中添加关联的服务提供者条目。
如果你还不了解 Laravel 服务提供者,我强烈建议你帮自己一个忙,阅读这篇介绍 Laravel 服务提供者基础知识的介绍性文章。
在我们的例子中,我们只需要将提供者添加到config/app.phpPassportServiceProvider
中的服务提供者列表中,如以下代码片段所示。
... ... '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 库创建必要的表。
$php artisan migrate
准确地说,它按照数据库中的表创建。
oauth_access_tokens oauth_auth_codes oauth_clients oauth_personal_access_clients oauth_refresh_tokens
创建一对公钥和私钥
接下来,我们需要生成一对公钥和私钥,Laravel Passport 库将使用它们进行加密。正如预期的那样,Passport 库提供了一个工匠命令来轻松创建它们。
$php artisan passport:install Encryption keys generated successfully. Personal access client created successfully. Client ID: 1 Client secret: ae2gNU5RnxucI9klOkKCLC76JVlbVYndE5v1Of70 Password grant client created successfully. Client ID: 2 Client secret: GQyBurXrkKwGrUahcls25GOB4yEnxScfmFlgb3io
那应该在storage/oauth-public.key和storage/oauth-private.key处创建密钥。它还创建了一些演示客户端凭据,我们稍后再讨论。
验证用户模型
继续前进,让我们对LaravelUser
用于身份验证的现有模型类进行 oauthify。为此,我们需要将HasApiTokens
特征添加到User
模型类中。让我们按照以下代码段所示进行操作。
<?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
trait 包含辅助方法,用于验证请求中的令牌并检查当前已验证用户上下文中所请求资源的范围。
注册护照路线
此外,我们需要将 Passport 库提供的路由注册到我们的 Laravel 应用程序中。这些路由将用于标准 OAuth2 操作,例如授权、请求访问令牌等。
在app/Providers/AuthServiceProvider.phpboot
文件的方法中,我们注册 Passport 库的路由。您还需要在此文件的开头添加该行。use Laravel\Passport\Passport
... /** * Register any authentication / authorization services. * * @return void */ public function boot() { $this->registerPolicies(); Passport::routes(); } ... ...
调整 API 驱动程序配置
最后但同样重要的是,我们需要在 config/auth.php 文件中将驱动程序从更改为,因为我们api
将使用 Passport 库进行 API 身份验证。token
passport
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', 'provider' => 'users', 'hash' => false, ], ],
到目前为止,我们已经完成了 OAuth2 服务器配置所需的一切。
设置演示资源
在上一节中,我们做了所有艰苦的工作来在我们的应用程序中设置 OAuth2 身份验证服务器。在本节中,我们将设置一个可以通过 API 调用请求的演示资源。
我们会尽量保持简单。如果请求uid
中存在有效参数,我们的演示资源将返回用户信息。GET
让我们使用以下内容创建一个控制器文件app/Http/Controllers/UserController.php 。
<?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 路由,如以下代码段所示。
<?php use Illuminate\Http\Request; /* |-------------------------------------------------------------------------- | API Routes |-------------------------------------------------------------------------- | | Here is where you can register API routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | is assigned the "api" middleware group. Enjoy building your API! | */ 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
,这就是您通过该路由请求资源时应该使用的。前缀由 Laravel 自动处理,api
您无需担心!
在下一部分和最后一部分中,我们将讨论如何创建客户端凭据并使用 OAuth2 API。
如何使用 OAuth2 API
现在我们已经在我们的应用程序中设置了 OAuth2 服务器,任何第三方都可以使用 OAuth 连接到我们的服务器并使用我们应用程序中可用的 API。
首先,第三方应用程序必须向我们的应用程序注册才能使用 API。换句话说,它们被认为是客户端应用程序,它们将在注册时收到一个客户端 ID 和客户端密码。
默认情况下,当您运行 PHPartisan passport:install
命令时,Passport 库已经创建了几个示例客户端。除此之外,它还允许您根据需要创建新客户端。Passport 库提供了一个工匠命令来轻松创建客户帐户。让我们继续创建一个演示客户帐户。
$php artisan passport:client Which user ID should the client be assigned to?: > 3 What should we name the client?: > Demo OAuth2 Client Account Where should we redirect the request after authorization? [https://localhost/auth/callback]: > http://localhost/oauth2_client/callback.php New client created successfully. Client ID: 3 Client secret: 1BT1tNj0Are27IGvIZe4lE2jRjtiVt0fmtaWBe8m
当您运行 artisanpassport:client
命令时,它会在创建客户帐户之前询问您几个问题。其中,有一个重要的问题会询问您callback URL
。
这callback URL
是用户在授权后将被重定向回第三方端的地方。这就是应该用于交换访问令牌的授权代码将被发送的地方。稍后我们将创建该文件。
现在,我们准备好在 Laravel 应用程序中测试 OAuth2 API。
出于演示目的,我将oauth2_client
首先在文档根目录下创建目录。理想情况下,这些文件将位于想要在我们的 Laravel 应用程序中使用 API 的第三方端。
让我们使用以下内容创建oauth2_client/auth_redirection.php文件。
<?php $query = http_build_query(array( 'client_id' => '3', '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文件。
<?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' => '3', 'client_secret' => '1BT1tNj0Are27IGvIZe4lE2jRjtiVt0fmtaWBe8m', '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 '. $access_token ); $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 } }
Again, make sure to adjust the URLs and client credentials according to your setup in the above file.
同样,请确保根据您在上述文件中的设置调整 URL 和客户端凭据。
它是如何工作的
在本节中,我们将从最终用户的角度对其进行全面测试。作为最终用户,您面前有两个应用程序:
第一个是您已经拥有帐户的 Laravel 应用程序。它保存您可以与其他第三方应用程序共享的信息。
第二个是演示第三方客户端应用程序auth_redirection.php和callback.php,它希望使用 OAuth API 从 Laravel 应用程序中获取您的信息。
流程从第三方客户端应用程序开始。继续并在浏览器中打开http://localhost/oauth2_client/auth_redirection.php URL,它应该会将您重定向到 Laravel 应用程序。如果你还没有登录 Laravel 应用程序,应用程序会要求你登录。
用户登录后,应用程序将显示授权页面。
如果用户授权该请求,用户将被重定向回位于http://localhost/oauth2_client/callback.php的第三方客户端应用程序以及包含授权代码的code
as参数。GET
一旦第三方应用程序收到授权码,它就可以与 Laravel 应用程序交换该码以获取访问令牌。这正是它在以下oauth2_client/callback.php文件片段中所做的。
$ch = curl_init(); $url = 'http://your-laravel-site-url/oauth/token'; $params = array( 'grant_type' => 'authorization_code', 'client_id' => '3', 'client_secret' => '1BT1tNj0Are27IGvIZe4lE2jRjtiVt0fmtaWBe8m', '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 应用程序访问用户信息的用例。我们已经在 Laravel 应用程序中构建了一个 API 端点http://your-laravel-site-url/api/user/get来促进它。
// 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 '. $access_token ); $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); }
这就是你应该如何在 Laravel 中使用 OAuth2 API 的完整流程。
至此,我们已经到了本文的结尾。
结论
今天,我们探索了 Laravel 中的 Laravel Passport 库,它允许我们非常轻松地在应用程序中设置 OAuth2 服务器。
- 安装 Laravel Passport 库
- 启用护照服务
- 创建数据库表
- 创建一对公钥和私钥
- 验证用户模型
- 注册护照路线
- 调整 API 驱动程序配置