|
@@ -6,21 +6,61 @@ use Closure;
|
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Request;
|
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
use Laravel\Sanctum\PersonalAccessToken;
|
|
use Laravel\Sanctum\PersonalAccessToken;
|
|
|
|
|
+use Webkul\BagistoApi\Services\ApiKeyService;
|
|
|
|
|
|
|
|
class ApiCustomerAuthenticate
|
|
class ApiCustomerAuthenticate
|
|
|
{
|
|
{
|
|
|
|
|
+ protected ?ApiKeyService $apiKeyService = null;
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Handle an incoming request.
|
|
* Handle an incoming request.
|
|
|
*
|
|
*
|
|
|
* 支持三种认证方式:
|
|
* 支持三种认证方式:
|
|
|
* 1. Session Cookie(传统 Web 登录)
|
|
* 1. Session Cookie(传统 Web 登录)
|
|
|
* 2. Sanctum Bearer Token(BagistoApi 登录)
|
|
* 2. Sanctum Bearer Token(BagistoApi 登录)
|
|
|
- * 3. Storefront Key + Customer Session
|
|
|
|
|
|
|
+ * 3. Storefront Key(X-STOREFRONT-KEY 请求头)→ 由 BagistoApi 的 ApiKeyService 统一验证
|
|
|
*
|
|
*
|
|
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
|
|
*/
|
|
*/
|
|
|
public function handle(Request $request, Closure $next): Response
|
|
public function handle(Request $request, Closure $next): Response
|
|
|
{
|
|
{
|
|
|
|
|
+ // 方式 3: Storefront Key 认证(X-STOREFRONT-KEY 请求头)
|
|
|
|
|
+ $storefrontKey = $request->header('X-STOREFRONT-KEY');
|
|
|
|
|
+ if ($storefrontKey) {
|
|
|
|
|
+ $apiKeyService = $this->getApiKeyService();
|
|
|
|
|
+
|
|
|
|
|
+ // 验证 key 有效性
|
|
|
|
|
+ $validation = $apiKeyService->validate(
|
|
|
|
|
+ $storefrontKey,
|
|
|
|
|
+ ApiKeyService::KEY_TYPE_SHOP,
|
|
|
|
|
+ $request->ip()
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (! ($validation['valid'] ?? false)) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'error' => 'invalid_storefront_key',
|
|
|
|
|
+ 'message' => $validation['message'] ?? 'The provided storefront key is invalid or inactive.',
|
|
|
|
|
+ ], 403);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 频率限制检查
|
|
|
|
|
+ $rateLimit = $apiKeyService->checkRateLimit($validation['client']);
|
|
|
|
|
+ if (! ($rateLimit['allowed'] ?? false)) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'error' => 'rate_limit_exceeded',
|
|
|
|
|
+ 'message' => 'Rate limit exceeded. Please retry later.',
|
|
|
|
|
+ 'retry_after' => $rateLimit['reset_at'] ?? 60,
|
|
|
|
|
+ ], 429);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $next($request);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'error' => 'invalid_storefront_key',
|
|
|
|
|
+ 'message' => 'X-STOREFRONT-KEY header is required',
|
|
|
|
|
+ ], 403);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 方式 1: Session Cookie 认证(传统 Web 登录)
|
|
// 方式 1: Session Cookie 认证(传统 Web 登录)
|
|
|
if (auth()->guard('customer')->check()) {
|
|
if (auth()->guard('customer')->check()) {
|
|
|
return $next($request);
|
|
return $next($request);
|
|
@@ -44,6 +84,14 @@ class ApiCustomerAuthenticate
|
|
|
], 401);
|
|
], 401);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 懒加载 ApiKeyService 实例
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function getApiKeyService(): ApiKeyService
|
|
|
|
|
+ {
|
|
|
|
|
+ return $this->apiKeyService ??= app(ApiKeyService::class);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 通过 Sanctum Token 验证客户
|
|
* 通过 Sanctum Token 验证客户
|
|
|
*
|
|
*
|