使用 Dingo API 快速构建 RESTful API(九)—— API 认证实现(下)
在上篇教程中,我们介绍了如何通过 HTTP 基本认证和 JWT 认证实现 Dingo API 的认证,这篇教程,学院君将会给大家介绍如何在 Dingo API 中基于 OAuth 2.0 和自定义认证驱动实现 API 认证。
OAuth 2.0 认证
和 Laravel Passport 一样,Dingo API 的 OAuth 2.0 认证基于第三方扩展包 league/oauth2-server 实现,该扩展包还提供了针对 Laravel 框架的适配包 lucadegasperi/oauth2-server-laravel,因此,在 Dingo API 中实现 OAuth 2 认证的话,直接安装配置后面这个扩展包即可。但是从 Laravel 5.3 开始,由于 Laravel 官方提供的 API 认证扩展包 Passport 也是基于 league/oauth2-server
实现的,所以后面这个适配包就废弃了,不仅如此,Dingo API 后续的版本也移除了 OAuth 2 驱动(Dingo\Api\Auth\Provider\OAuth2
),所以,如果你是在 Dingo API 包含 OAuth2 且 Laravel 框架版本低于 5.3 的老版本中实现 OAuth 2 认证,可以使用 lucadegasperi/oauth2-server-laravel
这个适配包快速实现,否则需要在 Dingo API 中自定义 OAuth2 驱动并自行配置 league/oauth2-server
实现 OAuth 2 认证,或者,你可以直接基于 Passport 实现 Dingo 的认证,包括上篇教程提到的 JWT 认证,也可以基于 Passport 实现(Passport 使用了另一个 JWT 扩展包实现基于 JWT 的 API 认证)。
在这篇教程中,为了简化流程,我们将直接基于 Passport 实现 Dingo API 的 OAuth2 认证(5.3 之前老版本实现可以参考 Dingo 文档),关于 OAuth2 的底层原理,可以参考 Passport 文档中的介绍,这里我们将重点放到认证实现上。
安装配置 Passport
如果你还没有在项目中安装并初始化 Passport 扩展包的话,可以参考 Passport 官方文档进行安装配置。这里由于我们基于待办任务项目进行演示,在之前的教程中已经初始化过,所以可以跳过这一步骤。
最后,记得将 config/auth.php
中的 guards.api.driver
配置值调整为 passport
以便在应用中生效:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
设置认证中间件
基于 Passport 认证的话,就需要修改之前设置的认证中间件了,打开 Api\TaskController.php
,将定义在构造函数中的认证中间件调整为 auth:api
:
public function __construct()
{
$this->middleware('auth:api');
}
这样一来,在认证的时候就会通过 Laravel 框架提供的中间件来校验了,此外,还需要修改获取认证用户的代码:
public function index(Request $request)
{
$limit = $request->input('limit') ? : 10;
// 获取当前认证用户实例
$user = $request->user();
$tasks = Task::where('user_id', $user->id)->paginate($limit);
return $this->response->paginator($tasks, new TaskTransformer());
}
通过密码授权令牌访问认证 API
OAuth 2 提供了多种获取授权令牌的方法,比如通过授权码颁发访问令牌、密码授权令牌、隐式授权令牌、私人访问令牌等,具体实现可以参考 Passport 官方文档或者学院君写的系列教程,这里我们以密码授权令牌为例做演示。
首先,我们通过如下 Artisan 命令创建一个新的需要接入 API 认证的客户端应用:
php artisan passport:client --password
这样一来,我们就获取到对应的 APP ID 和 APP Secret,将其配置到 .env
中:
CLIENT_ID=7
CLIENT_SECRET=7lz6yKdRWudXgwtct6esjwEjk8DpjjFs10lMkvFh
然后我们在 routes/api.php
中定义一个用于获取授权令牌的路由:
$api->version('v3', function ($api) {
...
$api->post('user/token', function () {
app('request')->validate([
'email' => 'required|string',
'password' => 'required|string',
]);
$http = new \GuzzleHttp\Client();
// 发送相关字段到后端应用获取授权令牌
$response = $http->post(route('passport.token'), [
'form_params' => [
'grant_type' => 'password',
'client_id' => env('CLIENT_ID'),
'client_secret' => env('CLIENT_SECRET'),
'username' => app('request')->input('email'), // 这里传递的是邮箱
'password' => app('request')->input('password'), // 传递密码信息
'scope' => '*'
],
]);
return response()->json($response->getBody()->getContents());
});
$api->resource('tasks', \App\Http\Controllers\Api\TaskController::class);
});
当我们在 Postman 中模拟访问 user/token
时,就可以获取到对应的访问令牌了:
其中 access_token
就是后续访问认证 API 时需要的令牌。还是在 Postman 中,我们将 access_token
字段值设置到类型为 Bearer 的 Authorization 字段,然后请求 tasks.index
路由,如果能返回相应的响应数据,表示认证成功:
至此,在 Dingo API 中基于 Passport 实现 OAuth2 认证就演示到这里,其它类型的 OAuth2 认证请参考学院君上篇提到的教程自行去实践。
自定义认证驱动
如果以上介绍的 HTTP 基本认证、JWT 认证以及 OAuth2 认证驱动都不能满足你的需求,你还可以选择在 Dingo 中自定义认证驱动。自定义认证驱动类需要实现 Dingo\Api\Contract\Auth\Provider
接口,如果认证成功,则返回对应的认证用户实例,否则要抛出 Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
异常:
use Illuminate\Http\Request;
use Dingo\Api\Routing\Route;
use Dingo\Api\Contract\Auth\Provider;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
class CustomProvider implements Provider
{
public function authenticate(Request $request, Route $route)
{
// Logic to authenticate the request.
throw new UnauthorizedHttpException('Unable to authenticate with supplied username and password.');
}
}
如果你需要使用从 Authorization
请求头中获取到的令牌,和 Dingo 默认提供的 Basic
和 JWT
驱动一样,可以选择继承 Dingo\Api\Auth\Provider\Authorization
基类,该基类也实现了 Dingo\Api\Contract\Auth\Provider
接口,只是新增了从 Authorization
请求头获取字段值的逻辑,我们在自定义驱动中只需要实现 getAuthorizationMethod
方法来返回 Authorization
请求头的认证类型即可:
use Illuminate\Http\Request;
use Dingo\Api\Routing\Route;
use Dingo\Api\Auth\Provider\Authorization;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
class CustomProvider extends Authorization
{
public function authenticate(Request $request, Route $route)
{
$this->validateAuthorizationHeader($request);
// If the authorization header passed validation we can continue to authenticate.
// If authentication then fails we must throw the UnauthorizedHttpException.
}
public function getAuthorizationMethod()
{
return 'mac';
}
}
定义完自定义驱动类就可以在配置文件 config/api.php
中配置通过自定义驱动实现 Dingo API 的认证:
'auth' => [
'custom' => 'CustomProvider',
],
或者在服务提供者的 boot
方法中扩展 Dingo 认证管理器驱动数组以便在应用中可以通过自定义驱动进行 API 认证:
app(\Dingo\Api\Auth\Auth::class)->extend('custom', function ($app) {
return new CustomProvider;
});
关于 Dingo API 的认证实现学院君就介绍到这里,下一篇教程我们将开始介绍 API 接口访问频率限制的实现。
No Comments