通过 Passport 实现 API 请求认证:开放平台篇(客户端凭证令牌)
前面两篇教程我们陆续介绍了通过密码授权获取令牌和通过授权码获取令牌访问需要认证的 API 接口,这篇教程我们来介绍第三种通过授权获取令牌的方式 —— 客户端凭证令牌。这种授权方式不需要走典型的登录或授权重定向流程,适用于机器与机器之间的接口认证,类似我们做微信、微博、支付宝开放平台开发,需要先申请自己的应用,申请通过后,这些开放平台会给我们分配对应的 APP ID 和 APP SECRET。然后我们通过这个 APP ID 和 APP SECRET 去开放平台获取 Token(令牌),最后拿着这个令牌去访问认证资源即可。今天我们要介绍的客户端凭证令牌也是这个思路。
我们还是以之前创建的测试项目 testapp
作为客户端应用,把后端项目 blog
作为类似微信的开放平台,为了简化流程,我们还是通过 Artisan 命令在后端注册客户端应用,免去申请流程,然后在客户端应用中通过分配的 APP ID 和 APP SECRET 获取授权令牌,最后拿着这个令牌访问后端认证接口。
在开放平台注册客户端应用
我们通过如下 Artisan 命令在后端应用 blog
中注册客户端应用:
php artisan passport::client
该命令执行成功后,会在 oauth_clients
表中新增一条记录,包含给客户端应用分配的 APP ID 和 APP SECRET 信息,分别是 id
字段和 secret
字段。
更新第三方应用的配置信息
回到客户端应用 testapp
,修改 .env
中的 CLIENT_ID
和 CLIENT_SECRET
配置:
CLIENT_ID=11
CLIENT_SECRET=XKmtGXC1CdG2LvhUpdp3y81IjuyrP0rLUPPq8reg
config/services.php
中的 blog
配置项保持不变。
在客户端应用中定义路由和控制器
接下来,我们在客户端应用中定义获取令牌的路由,在 routes/web.php
新增下面行代码:
Route::get('/auth/client', 'Auth\LoginController@client');
然后在 LoginController
控制器中编写对应的 client
方法:
public function client()
{
$http = new Client();
$response = $http->post('http://blog.test/oauth/token', [
'form_params' => [
'grant_type' => 'client_credentials',
'client_id' => config('services.blog.appid'), // your client id
'client_secret' => config('services.blog.secret'), // your client secret
'scope' => '*'
],
]);
return response($response->getBody());
}
注意到我们在获取令牌的请求数据中将 grant_type
类型设置为了 client_credentials
,意为通过客户端凭证颁发访问令牌。
至此,我们就完成了完整的获取客户端凭证令牌的代码编写和配置工作,接下来简单测试下这个流程。
测试客户端应用访问开放平台认证接口
首先在浏览器中访问 http://app.test/auth/client
,就可以获取到访问令牌了:
需要注意的是,客户端访问令牌默认长期有效,所以这里没有返回用于刷新令牌的 refresh_token
字段。接下来,我们就可以通过将返回的 access_token
值添加到 Bearer Authentication 请求头中,来访问开放平台 blog
中需要认证的 API 接口了。
在测试认证 API 接口之前,我们还需要在后端应用的 routes/api.php
中新增一个测试路由:
Route::middleware('client')->get('/test', function (Request $request) {
return '欢迎访问 Laravel 学院!';
});
不同于之前需要检测用户认证的 auth:api
中间件,我们在这个路由中应用了 client
中间件,表示该路由需要通过客户端凭证访问令牌进行认证才能访问,接下来,我们在 app/Http/Kernel.php
的 $routeMiddleware
属性中定义这个中间件:
'client' => \Laravel\Passport\Http\Middleware\CheckClientCredentials::class,
这样,我们就可以在 Postman 中测试这个 API 接口的访问了,如果不添加 Bearer Token 请求头,返回结果如下:
如果将上述 /auth/client
请求返回的 access_token
值添加到 Bearer Token 请求头中,就可以获取到对应的接口返回数据了:
结语
我们以开放平台为例,分两篇教程介绍了相关的 API 接口认证实现方式,对于需要用户主动授权,与用户个人资源信息强相关的接口,需要通过授权码获取令牌的方式进行认证;对于与具体用户无关的资源,但需要认证才能访问的接口,可以通过本篇教程介绍的这种客户端凭证访问令牌的方式进行认证,免去了跳转认证、重定向的复杂流程。此外,这种客户端凭证访问令牌认证使用范围不仅局限于开放平台,也可以作为后端服务接口的认证实现方式,对公司内部提供认证 API,从而提高接口的安全性。
11 Comments
最近关于客户端令牌,遇见了新的问题:我使用possport的 client_credentials 验证,两个客户端项目接入。不同的client-id 和 client-secret,A客户端的令牌能连接的上。但是B客户通过B客户端所拥有的client-id 和 client-secret拿到的令牌,却不能访问,是401,然后当我在B客户端使用A客户端的令牌,却可以正常访问。不是应该是不同的客户端不同的令牌吗