说明#
此文章是 [Laravel 5.3 新功能] 系列的第十一篇文章,Laravel Passport 介绍。
[Laravel 5.3 新功能] 系列完整文章列表请见:https://laravel-china.org/topics/2638
注意事项#
在编写此文章时,Passport 还未正式发布,因此可能会和发布版本有所出入。我会在其正式发布后第一时间更新此文章。
什么是 Laravel Passport#
API 的身份验证是我们开发中最棘手的部分。OAuth 是你可以考虑的比较严格的验证方式,但是它比较难集成。我们曾经有讨论过使用多个路由、migration、复杂的配置等等来简化身份验证的集成难度,但实际上集成此服务还是过于复杂。
不过,在 5.3 以后出现了 Laravel Passport,它是一个为 Laravel 提供原生 OAuth 2 服务的组件。类似于 Cashier 和 Scout,你可通过 Composer 将其安装到你的 Laravel 应用程序中,而且它集成非常简单。
Laravel 5.2 中身份认证的弊端#
在 Laravel 5.2 里,我们利用多目录来为身份认证提供多个 auth 认证服务,这意味着你可以在不同的环境中使用不同的身份认证方式(如 web 和 api,或者生产环境和开发环境)。
在 5.2 中,默认的 token 的身份验证机制已经足够使用了,但是它对于需要登录操作的业务来说不够安全,所以我们需要 passport
来提供更安全的 OAuth2 认证机制。
安装 Passport#
1)、运行下面的命令,通过 Composer 安装 Passport
composer require laravel/passport
2)、打开你的 config/app.php
文件,将 Laravel\Passport\PassportServiceProvider
添加到 $providers
属性中。
3)、运行 migrations
php artisan migrate
4)、打开你的 User
类,并引入 Laravel\Passport\HasApiTokens
traits。
5)、在你的 AuthServiceProvider
文件中引入 use Laravel\Passport\Passport
,然后在 boot() 方法中添加 OAuth2 路由方法 Passport::routes()
// AuthServiceProvider
public function boot()
{
Passport::routes();
}
6)、 加入 Passport::tokensCan()
方法
// AuthServiceProvider
public function boot()
{
Passport::route();
Passport::tokensCan([
'conference' => 'Access your conference information'
]);
}
7)、在 config/auth.php
文件中,修改 guards.api.driver
配置,将 driver
设置为 passport
:
// config/auth.php
return [
...
'guards' => [
...
'api' => [
'driver' => 'passport', // was previously 'token'
'provider' => 'users'
]
]
];
这样就全部配置成功了,非常简单吧。接下来将讲解如何管理你的客户端和 token。
Passport 如何管理 API#
Passport 通过 JSON 格式的 API 提供服务给客户端,这些 API 都提供了管理(新增、删除等)客户端和个人 token 的方法。
Passport 默认使用 Vue 组件来展示你的 API,你可以使这个组件来展示和管理你的 API。当然,你也可以编写自定义的工具来集成 API。
Passport 默认使用 Vue 框架#
Passport 使用了三个 Vue 组件:
<!-- let people make clients -->
<passport-clients></passport-clients>
<!-- list of clients people have authorized to access our account -->
<passport-authorized-clients></passport-authorized-clients>
<!-- make it simple to generate a token right in the UI to play with -->
<passport-personal-access-tokens></passport-personal-access-tokens>
我们来分析一下它们都做了什么。
在 Laracon 上,Taylor 做了一个例子。他先在 http://passport.dev/
应用程序上安装了 Passport
,使其能提供 OAuth 服务。然后他再创建一个 http://consumer.dev/
应用程序作为客户端,下文中我们称其为 consumer
。
下面是他展示的管理界面(使用了上文提到的 vue 的三个组件)
下面是创建 client 的界面
当你创建完 client 后,你会获得一个 client ID,现在将此 ID 放到上文提到的 consumer
应用程序中,写入到其配置文件里。
下面是 Taylor 展示的 consumer
应用程序路由:
// routes/web.php
use Illuminate\Http\Request;
// First route that user visits on consumer app
Route::get('/', function () {
// Build the query parameter string to pass auth information to our request
$query = http_build_query([
'client_id' => 1,
'redirect_uri' => 'http://consumer.dev/callback',
'response_type' => 'code',
'scope' => 'conference'
]);
// Redirect the user to the OAuth authorization page
return redirect('http://passport.dev/oauth/authorize?' . $query);
});
// Route that user is forwarded back to after approving on server
Route::get('callback', function (Request $request) {
$http = new GuzzleHttp\Client;
$response = $http->post('http://passport.dev/oauth/token', [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => 1, // from admin panel above
'client_secret' => 'abc', // from admin panel above
'redirect_uri' => 'http://consumer.dev/callback`,
'code' => $request->code // Get code from the
]
]);
return json_decode((string) $response->getBody(), true)['access_token'];
});
当你使用配置好的 client ID 等数据访问 http://consumer.dev/
时,它会自动重定向到 http://passport.dev/
里。
当你认证成功后,Passport 将重定向回你的 callback URL,在上文的例子中,它将重定向回 http://consumer.dev/callback
,现在你将获得一个 token,通过这个 token 你能获取到用户的相关权限。
测试你的 token#
在轻松的做完这一切后,Taylor 在他的 Passport
应用程序中创建了一个路由文件 routes/api.php
,我们看一下如何使用其便捷的测试你的 API。
首先,在 Passport
应用程序路由中添加以下代码:
// routes/api.php
Route::get('/user', function (Request $request) {
return $request->user();
});
由于在 routes/api.php
中的所有路由会自动加载 API 中间件,所以它会自动条用 auth:api
来验证用户。
接下来,打开你常用的 REST 客户端(如 Postman,Paw 又或者是你自己手写 PHP 代码请求接口)请求接口 http://passport.dev/api/user
,当然你首先需要确认你的请求中 header 的 Content-Type
和接收信息中 header 的 Accept
都为 application/json
。
如果验证不通过,你会收到 401 回应:
{
"error": "Unauthenticated."
}
现在,你想起来 access token 没?复制这个 token,然后将其加入到你请求 header 的 Authorization
中,设置它的值为 Bearer: TOKENHERE
,TOKENHERE 就是你刚才获取复制的 token 了。现在,你应该能看到正常的返回值了:
{
"id": 1,
"name": "Matt Stauffer",
"email": "matt@mattstauffer.co",
"created_at": "2016-07-30 10:45:00",
"updated_at": "2016-07-30 10:45:00"
}
就这样,你就快速的配置好你的 OAuth 2 API 了。
Passport 还有其他的功能,我们一起来看一下。
管理客户端 token 界面#
请记住,这只是一个示范界面,你不一定使用 vue 来构建这个界面。
Passport 提供了非常有用的工具来创建测试 token,你不需要再创建一个完整的 consumer
应用程序来测试你的 API,你可以创建 personal tokens
来进行测试:
php artisan make passport:client --personal
现在你可以去 Personal Access Tokens 界面点击 “Create New Token” 按钮,它将生成新的 token。你可以删除这个 token,就像你可以撤销你的 client tokens 一样。
Scope 中间件#
使用 scope 可以定义你的应用程序中的每个请求可以使用何种中间件。每个 scope 都有名称和描述,这样方便在程序中调用。
我们现在来看一下如何简单高效的定义 scope 中间件。
现在你的应用程序中有两个中间件,你可以给他们添加别名方便你快速调用,在这里我们分别起名为 anyScope
和 allScopes
。
现在修改一下 app/Http/Kernel.php
文件:
// App\Http\Kernel
...
protected $routeMiddleware = [
...
// you can name these whatever you want
'anyScope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
'allScopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
];
现在,在每个路由后面你都可以调用这两个中间件进行访问权限控制,如果你使用 anyScope
,则当用户拥有任一指定的 scope 即可访问该路由。如果你使用 allScopes
,则用户必须拥有所有指定的 scope 才可以访问该路由。
在下面的例子中,程序将限制用户的访问权限,除非他们有 conference
scope。
Route::get('/whatever', function () {
// do stuff
})->middleware('anyScope:conference');
// Any of the given scopes
Route::get('/whatever', function () {
// do stuff
})->middleware('anyScope:conference,otherScope');
// All of the given scopes
Route::get('/whatever', function () {
// do stuff
})->middleware('allScopes:conference,otherScope');
结语#
我编写过很多的 OAuth 服务,这过程非常痛苦。Passport 是我非常喜欢的新功能,不仅仅是因为它简化了我之前非常痛恨的集成,它还提供了很多我之前没想到的新功能,我现在很迫不及待的想使用它。
全文完