Skip to main content

API 认证

在返回响应之前,大多数 API 需要通过某种形式的身份验证。 有时,经过和未经过身份验证的请求,响应的内容会有所不同。

这个软件包允许您配置多个身份验证提供者。 当启用身份验证后,每一个提供者都会尝试对请求进行身份验证。

配置身份验证提供者

默认情况下,仅在配置文件中启用 HTTP 基本身份验证。以下是该包内置支持身份验证提供者的列表:

  • HTTP Basic (Dingo\Api\Auth\Provider\Basic)
  • JSON Web Tokens (Dingo\Api\Auth\Provider\JWT)
  • OAuth 2.0 (Dingo\Api\Auth\Provider\OAuth2)

HTTP 基本验证

这个服务提供者使用 laravellumen 中内置的默认基本身份验证。 您需要在配置文件或者引导文件中配置此服务提供者,第二个参数用于认证的标识符。

app('Dingo\Api\Auth\Auth')->extend('basic', function ($app) {
return new Dingo\Api\Auth\Provider\Basic($app['auth'], 'email');
});

JSON Web Tokens (JWT)

tymon/jwt-auth 是使用第三方来集成 JWT 身份验证的软件包。 有关安装和配置的详细信息,请参阅 GitHub 页面。

一旦您安装了这个软件包,您就可以在 config/api.php 文件或者引导文件中配置该服务提供者。

'auth' => [
'jwt' => 'Dingo\Api\Auth\Provider\JWT',
],
app('Dingo\Api\Auth\Auth')->extend('jwt', function ($app) {
return new Dingo\Api\Auth\Provider\JWT($app['Tymon\JWTAuth\JWTAuth']);
});

OAuth 2.0

这个包是使用第三方来集成的 OAuth 2.0 。 您可以安装 league/oauth2-server 并配置服务提供者,或者,您也可以使用 lucadegasperi/oauth2-server-laravel

为了简单起见,以下例子将使用 lucadegasperi/oauth2-server-laravel 这个 Laravel 定制包。

一旦您安装了这个包,您需要配置 provider 或者 bootstrap 文件。

app('Dingo\Api\Auth\Auth')->extend('oauth', function ($app) {
$provider = new Dingo\Api\Auth\Provider\OAuth2($app['oauth2-server.authorizer']->getChecker());

$provider->setUserResolver(function ($id) {
// 获取用户 ID 的代码逻辑
});

$provider->setClientResolver(function ($id) {
// 通过 Client ID 获取 OAuth Client 的逻辑
});

return $provider;
});

或者配置服务提供者。

namespace App\Providers;

use Dingo\Api\Auth\Auth;
use Dingo\Api\Auth\Provider\OAuth2;
use Illuminate\Support\ServiceProvider;

class OAuthServiceProvider extends ServiceProvider
{
public function boot()
{
$this->app[Auth::class]->extend('oauth', function ($app) {
$provider = new OAuth2($app['oauth2-server.authorizer']->getChecker());

$provider->setUserResolver(function ($id) {
// 获取用户 ID 的代码逻辑
});

$provider->setClientResolver(function ($id) {
// 通过 Client ID 获取 OAuth Client 的逻辑
});

return $provider;
});
}

public function register()
{
//
}
}

用户和客户端解析器

根据授权许可,您可能不需要2个解析器。例如:如果您只需要客户端通过 OAuth 2.0 身份验证,则不需要配置用户解析器。

解析器都接收用户或者客户端的 ID,并用这个 ID 返回用户或者客户端的实例。这通常涉及用户或者客户端的数据库查询。

自定义身份验证

如果您正在维护以前的系统或者需要其他形式的身份验证,则可以实施自定义身份验证。

您的身份验证提供者应该实现 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)
{
// 对请求进行验证的逻辑

throw new UnauthorizedHttpException('Unable to authenticate with supplied username and password.');
}
}

Dingo\Api\Auth\Provider\Authorization 将颁发一个带 Authorization 头信息的 tokenDingo\Api\Auth\Provider\Authorization::validateAuthorizationHeader 可以轻松的验证 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);

// 如果 Authorization 通过验证,我们可以继续进行身份验证
// 如果 Authorization 验证失败, 我们必须抛出一个 UnauthorizedHttpException 的异常。
}

public function getAuthorizationMethod()
{
return 'mac';
}
}

一旦您实现了自己的身份验证提供者,您需要在 config/api.php 这个文件进行配置。

'auth' => [
'custom' => 'CustomProvider',
],

或者,配置 bootstrapprovider 文件。

app('Dingo\Api\Auth\Auth')->extend('custom', function ($app) {
return new CustomProvider;
});

保护级别

您可以通过 api.auth 路由中间件来启用路由或者路由群组的保护。

如果您使用 Laravel 的定制包。则可以直接使用 api.auth 这个中间件。并且不需要注册。

在所有的路由上启用

$api->version('v1', ['middleware' => 'api.auth'], function ($api) {
// 在这个版本群组下的所有路由将进行身份验证。
});

特定的路由上启用

$api->version('v1', function ($api) {
$api->get('user', ['middleware' => 'api.auth', function () {
// 这个路由将进行身份验证。
}]);

$api->get('posts', function () {
// 这个路由不会验证身份。
});
});

只允许特定的身份验证提供者

如果你想在一个群组或者特定的路由上验证身份验证提供者。你可以启用 providers 来配置。

$api->version('v1', function ($api) {
$api->get('user', ['middleware' => 'api.auth', 'providers' => ['basic', 'oauth'], function () {
// 这个路由将进行身份验证。
}]);
});

控制器上进行身份验证

LaravelLumen 都可以在控制器里启用中间件。您可以在构造函数里使用 middleware 的方法。

class UserController extends Illuminate\Routing\Controller
{
use Helpers;

public function __construct()
{
$this->middleware('api.auth');

// 这个中间件只在 index 中启用
$this->middleware('api.auth', ['only' => ['index']]);
}

public function index()
{
//
}

public function posts()
{
//
}
}

检索经过身份验证的用户

你可以在受保护的接口里检索已通过身份验证的用户

$api->version('v1', ['middleware' => 'api.auth'], function ($api) {
$api->get('user', function () {
$user = app('Dingo\Api\Auth\Auth')->user();

return $user;
});
});

如果你的控制器里使用了 Dingo\Api\Routing\Helpers 那么你就可以使用 $auth

use Dingo\Api\Routing\Helpers;
use Illuminate\Routing\Controller;

class UserController extends Controller
{
use Helpers;

public function __construct()
{
$this->middleware('api.auth');
}

public function index()
{
$user = $this->auth->user();

return $user;
}
}

可选的验证

有时你可能需要根据请求是否通过身份验证来修改响应值,为此,路由不应该设置中间件去保护,你只需要手动认证用户。

$api->version('v1', function ($api) {
$api->get('users/{id}', function ($id) {
$user = User::findOrFail($id);

// 尝试验证请求。如果请求未被认证那么我们会从响应中隐藏电子邮件。只认证
// 请求可以看到其他用户的电子邮件。

if (! app('Dingo\Api\Auth\Auth')->user()) {
$hidden = $user->getHidden();

$user->setHidden(array_merge($hidden, ['email']));
}

return $user;
});
});