编程

Laravel 使用 Scramble 文档化 API 身份认证

124 2025-03-21 02:05:00

本文中,我们将回顾 Laravel 中常见的 API 身份验证方法,以及如何使用 Scramble(Laravel 的现代 API 文档工具)文档化这些方法。

OpenAPI 规范支持多种 API 身份验证方法。通过最近的更新,Scramble 现在完全支持 OpenAPI 3.1.0 安全规范,允许你文档化规范中可用的任何身份验证方法。

Sanctum 身份验证

对于无状态身份验证,Sanctum 允许你在 Authorization 标头中发送身份验证令牌:

Authorization: Bearer ***

使用 Scramble,你可以使用以下代码文档化此身份验证。它应该添加到任何服务提供商的 boot 方法中:

use Dedoc\Scramble\Scramble;
use Dedoc\Scramble\Support\Generator\OpenApi;
use Dedoc\Scramble\Support\Generator\SecurityScheme;
 
public function boot()
{
    Scramble::configure()
        ->withDocumentTransformers(function (OpenApi $openApi) {
            $openApi->secure(
                SecurityScheme::http('bearer')
            );
        });
}

这将为所有端点设置默认安全方案。

如果你使用 Sanctum 的有状态身份验证,并且 Scramble 的文档路由在正确的域上,你的身份验证会话将在“试用”中自动工作。

Passport 身份验证

对于 OAuth2 身份验证,OpenAPI 提供了 oauth2 安全方案。

Scramble 允许你精确指定 oauth2 的工作原理:

use Dedoc\Scramble\Scramble;
use Dedoc\Scramble\Support\Generator\OpenApi;
use Dedoc\Scramble\Support\Generator\SecurityScheme;
use Dedoc\Scramble\Support\Generator\SecuritySchemes\OAuthFlow;
 
public function boot()
{
    Scramble::configure()
        ->withDocumentTransformers(function (OpenApi $openApi) {
            $openApi->secure(
                SecurityScheme::oauth2()
                    ->flow('authorizationCode', function (OAuthFlow $flow) {
                        $flow
                            ->authorizationUrl(config('app.url').'/oauth/authorize')
                            ->tokenUrl(config('app.url').'/oauth/token')
                            ->addScope('*', 'all');
                        })
                );
        });
}

你可以按此处所示定义所有 Scope,也可以为应用指定粒度 Scope。

Stoplight Elements UI(Scramble 的默认 UI)显示 oauth2 要求,而其他 UI(Scalar、Swagger)也允许用户直接从文档中获取 API 令牌。

文档化 Sanctum 的 oauth/token 端点

你可以使用 Scramble 文档化 Sanctum 的 oauth/token 端点。这是一个社区创建的扩展,可以帮助实现这一点:https://gist.github.com/tech-codivores/ddce2b10a64f06fe0b1bcd4868c17039

在使用扩展之前,请确保将其包含在 Scramble 的可文档化路由中:

Scramble::configure()
    ->routes(function (Route $r) {
        return Str::startsWith($r->uri, 'api/'])
            || $r->uri === 'oauth/token';
    })

自定义身份认证

多 header 身份认证

如果你的身份认证需要多个 header,你可以在 API 安全要求中指定它们:

use Dedoc\Scramble\Scramble;
use Dedoc\Scramble\Support\Generator\OpenApi;
use Dedoc\Scramble\Support\Generator\SecurityScheme;
 
public function boot()
{
    Scramble::configure()
        ->withDocumentTransformers(function (OpenApi $openApi) {
            $openApi->components->securitySchemes['tenant'] = SecurityScheme::apiKey('header', 'X-Tenant');
            $openApi->components->securitySchemes['bearer'] = SecurityScheme::http('bearer');
 
            $openApi->security[] = new SecurityRequirement([
                'tenant' => [],
                'bearer' => [],
            ]);
        });
}

本例中,认证需要 X-TenentAuthorzation header。

查询参数中的 API token

如果你的 API token 作为查询参数传递,你可以使用这段代码将其文档化:

use Dedoc\Scramble\Scramble;
use Dedoc\Scramble\Support\Generator\OpenApi;
use Dedoc\Scramble\Support\Generator\SecurityScheme;
 
public function boot()
{
    Scramble::configure()
        ->withDocumentTransformers(function (OpenApi $openApi) {
            $openApi->secure(
                SecurityScheme::apiKey('query', 'api_token');
            );
        });
}

你可以在 Scramble 文档中了解更多安全方案:https://scramble.dedoc.co/usage/authentication.

从身份认证要求中排除路由

使用 @unauthenticated PHPDoc 注解,可以在身份认证中排除指定路由:

/**
 * @unauthenticated
 */
public function index(Request $request)
{
    return response()->json(/* some data */);
}

 而 operation transformers 提供了更大的灵活性。

比如,要从没有 auth: 中间件的路由中删除身份验证要求:

public function boot()
{
    Scramble::configure()
        ->withOperationTransformers(function (Operation $operation, RouteInfo $routeInfo) {
            $routeMiddleware = $routeInfo->route->gatherMiddleware();
 
            $hasAuthMiddleware = collect($routeMiddleware)->contains(
                fn ($m) => Str::startsWith($m, 'auth:')
            );
 
            if (! $hasAuthMiddleware) {
                $operation->security = [];
            }
        })
}

这会自动将没有身份验证中间件的路由标记为公共路由(public)。使用这种方法,你还可以为操作分配特定的安全要求。

小结

实现 API 身份验证的方法有很多,而 OpenAPI 涵盖了其中的大部分。

使用 Scramble,你可以文档化 API 的身份验证设置,甚至可以基于中间件自动化身份验证需求,从而避免手动注释。

如果你还没有尝试过 Scramble,试试吧! https://scramble.dedoc.co