afa 5 mēneši atpakaļ
vecāks
revīzija
21c4047598

+ 1 - 1
app/api/controller/Base.php

@@ -70,7 +70,7 @@ class Base
      * @param string|null $type 输出类型
      * @param array $header 发送的 Header 信息
      */
-    protected function error(string $msg = '', $data = null, int $code = 400, string $type = null, array $header = [])
+    protected function error(string $msg = '', $data = null, int $code = 0, string $type = null, array $header = [])
     {
         if (empty($msg)) {
             $msg = "操作失败";

+ 24 - 23
app/api/middleware/AllowCrossDomain.php

@@ -9,19 +9,7 @@ use think\Response;
 
 class AllowCrossDomain{
     
-    protected $cookieDomain;
-
-    protected $header = [
-        'Access-Control-Allow-Credentials' => 'true',
-        'Access-Control-Max-Age'           => 1800,
-        'Access-Control-Allow-Methods'     => 'GET, POST, PATCH, PUT, DELETE, OPTIONS',
-        'Access-Control-Allow-Headers'     => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With',
-    ];
-
-    public function __construct(Config $config)
-    {
-        $this->cookieDomain = $config->get('cookie.domain', '');
-    }
+   
 
     /**
      * 允许跨域请求
@@ -33,17 +21,30 @@ class AllowCrossDomain{
      */
     public function handle(Request $request, Closure $next, array $header = []): Response
     {
-        $header = !empty($header) ? array_merge($this->header, $header) : $this->header;
-
-        if (!isset($header['Access-Control-Allow-Origin'])) {
-            $origin = $request->header('origin');
-
-            if ($origin && ('' == $this->cookieDomain || str_contains($origin, $this->cookieDomain))) {
-                $header['Access-Control-Allow-Origin'] = $origin;
-            } else {
-                $header['Access-Control-Allow-Origin'] = '*';
-            }
+       
+        // 从配置文件中获取允许的域名列表
+        // 允许的源  
+        // 从.env文件读取配置并转换为数组
+        $allowedOriginsStr = env('CORS_ALLOWED_ORIGINS', '');
+        $allowedOrigins = explode(',', $allowedOriginsStr);
+        $origin = $request->header('Origin');
+
+        dump($origin);die;
+        if (in_array($origin, $allowedOrigins)) {
+            header('Access-Control-Allow-Origin: '. $origin);
+        } else {
+
+            // 处理不允许的来源,例如返回403错误
+            return response()->code(403)->data(['message' => 'Forbidden']);
+        }
+        header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
+        header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
+        header('Access-Control-Allow-Credentials: true');
+        if ($request->method() === 'OPTIONS') {
+            return response()->code(204);
         }
+         
+        
 
         return $next($request)->header($header);
     }

+ 2 - 2
app/api/route/route.php

@@ -12,8 +12,8 @@ Route::group('user', function () {
       Route::rule('getTxhashDetail','transaction/getTxhashDetail','GET|POST');
       Route::rule('createAddress','transaction/createAddress','GET|POST');
 
-    // \think\middleware\AllowCrossDomain::class
-})->middleware(\think\middleware\AllowCrossDomain::class);
+    //
+})->middleware(\app\api\middleware\AllowCrossDomain::class);
 
 
 

+ 2 - 1
composer.json

@@ -29,7 +29,8 @@
         "topthink/think-annotation": "^2.0",
         "symfony/http-foundation": "^6.3",
         "phpoffice/phpspreadsheet": "^1.29",
-        "topthink/think-captcha": "^3.0"
+        "topthink/think-captcha": "^3.0",
+        "topthink/think-cors": "^1.0"
     },
     "require-dev": {
         "symfony/var-dumper": ">=4.2"

+ 57 - 1
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "2335a25344887e3d6d0a2c271c8ef226",
+    "content-hash": "bbed793c5d6b8394cf660d85e47a23e1",
     "packages": [
         {
             "name": "composer/pcre",
@@ -1738,6 +1738,62 @@
             },
             "time": "2025-01-07T08:19:23+00:00"
         },
+        {
+            "name": "topthink/think-cors",
+            "version": "v1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/think-cors.git",
+                "reference": "822d90b357daa5aa5e1d01668615599f428ad132"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/think-cors/zipball/822d90b357daa5aa5e1d01668615599f428ad132",
+                "reference": "822d90b357daa5aa5e1d01668615599f428ad132",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "topthink/framework": "^6.0|^8.0"
+            },
+            "type": "library",
+            "extra": {
+                "think": {
+                    "config": {
+                        "cors": "src/config.php"
+                    },
+                    "services": [
+                        "think\\cors\\Service"
+                    ]
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "think\\cors\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "yunwuxin",
+                    "email": "448901948@qq.com"
+                }
+            ],
+            "description": "The Cors Library For ThinkPHP",
+            "support": {
+                "issues": "https://github.com/top-think/think-cors/issues",
+                "source": "https://github.com/top-think/think-cors/tree/v1.0.2"
+            },
+            "time": "2024-04-26T06:32:17+00:00"
+        },
         {
             "name": "topthink/think-filesystem",
             "version": "v2.0.3",

+ 1 - 1
config/app.php

@@ -40,7 +40,7 @@ return [
           //保持登陆时间,单位秒
          'keepalive_time'=>24*3600*30,
          //用户信息保存适配器,更换适配器需要实现app\api\service\auth\Adapter接口
-         'adapter'=>app\api\service\auth\MysqlAdapter::class,
+        
     ],
     //平台配置
     'platform_list'              => [

+ 12 - 0
config/cors.php

@@ -0,0 +1,12 @@
+<?php
+
+return [
+    'paths'                    => ['api/*'],
+    'allowed_origins'          => ['*'],
+    'allowed_origins_patterns' => [],
+    'allowed_methods'          => ['*'],
+    'allowed_headers'          => ['*'],
+    'exposed_headers'          => [],
+    'max_age'                  => 0,
+    'supports_credentials'     => false,
+];

+ 0 - 4
route/route.php

@@ -1,4 +0,0 @@
-<?php
-use think\facade\Route;
-
-

+ 3 - 2
vendor/composer/autoload_psr4.php

@@ -7,10 +7,11 @@ $baseDir = dirname($vendorDir);
 
 return array(
     'think\\view\\driver\\' => array($vendorDir . '/topthink/think-view/src'),
+    'think\\cors\\' => array($vendorDir . '/topthink/think-cors/src'),
     'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'),
     'think\\app\\' => array($vendorDir . '/topthink/think-multi-app/src'),
     'think\\annotation\\' => array($vendorDir . '/topthink/think-annotation/src'),
-    'think\\' => array($vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-container/src', $vendorDir . '/topthink/think-validate/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-filesystem/src', $vendorDir . '/topthink/think-template/src'),
+    'think\\' => array($vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-container/src', $vendorDir . '/topthink/think-filesystem/src', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/think-template/src', $vendorDir . '/topthink/think-validate/src'),
     'app\\' => array($baseDir . '/app'),
     'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
     'Symfony\\Polyfill\\Php83\\' => array($vendorDir . '/symfony/polyfill-php83'),
@@ -19,7 +20,7 @@ return array(
     'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
     'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
     'Psr\\Log\\' => array($vendorDir . '/psr/log/src'),
-    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),
+    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
     'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
     'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
     'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),

+ 13 - 8
vendor/composer/autoload_static.php

@@ -22,6 +22,7 @@ class ComposerStaticInitda8298e611526d4409180cd4bea64bcc
         't' => 
         array (
             'think\\view\\driver\\' => 18,
+            'think\\cors\\' => 11,
             'think\\captcha\\' => 14,
             'think\\app\\' => 10,
             'think\\annotation\\' => 17,
@@ -78,6 +79,10 @@ class ComposerStaticInitda8298e611526d4409180cd4bea64bcc
         array (
             0 => __DIR__ . '/..' . '/topthink/think-view/src',
         ),
+        'think\\cors\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/topthink/think-cors/src',
+        ),
         'think\\captcha\\' => 
         array (
             0 => __DIR__ . '/..' . '/topthink/think-captcha/src',
@@ -92,13 +97,13 @@ class ComposerStaticInitda8298e611526d4409180cd4bea64bcc
         ),
         'think\\' => 
         array (
-            0 => __DIR__ . '/..' . '/topthink/think-helper/src',
+            0 => __DIR__ . '/..' . '/topthink/framework/src/think',
             1 => __DIR__ . '/..' . '/topthink/think-container/src',
-            2 => __DIR__ . '/..' . '/topthink/think-validate/src',
-            3 => __DIR__ . '/..' . '/topthink/think-orm/src',
-            4 => __DIR__ . '/..' . '/topthink/framework/src/think',
-            5 => __DIR__ . '/..' . '/topthink/think-filesystem/src',
-            6 => __DIR__ . '/..' . '/topthink/think-template/src',
+            2 => __DIR__ . '/..' . '/topthink/think-filesystem/src',
+            3 => __DIR__ . '/..' . '/topthink/think-helper/src',
+            4 => __DIR__ . '/..' . '/topthink/think-orm/src',
+            5 => __DIR__ . '/..' . '/topthink/think-template/src',
+            6 => __DIR__ . '/..' . '/topthink/think-validate/src',
         ),
         'app\\' => 
         array (
@@ -134,8 +139,8 @@ class ComposerStaticInitda8298e611526d4409180cd4bea64bcc
         ),
         'Psr\\Http\\Message\\' => 
         array (
-            0 => __DIR__ . '/..' . '/psr/http-message/src',
-            1 => __DIR__ . '/..' . '/psr/http-factory/src',
+            0 => __DIR__ . '/..' . '/psr/http-factory/src',
+            1 => __DIR__ . '/..' . '/psr/http-message/src',
         ),
         'Psr\\Http\\Client\\' => 
         array (

+ 59 - 0
vendor/composer/installed.json

@@ -1839,6 +1839,65 @@
             },
             "install-path": "../topthink/think-container"
         },
+        {
+            "name": "topthink/think-cors",
+            "version": "v1.0.2",
+            "version_normalized": "1.0.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/think-cors.git",
+                "reference": "822d90b357daa5aa5e1d01668615599f428ad132"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/think-cors/zipball/822d90b357daa5aa5e1d01668615599f428ad132",
+                "reference": "822d90b357daa5aa5e1d01668615599f428ad132",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "topthink/framework": "^6.0|^8.0"
+            },
+            "time": "2024-04-26T06:32:17+00:00",
+            "type": "library",
+            "extra": {
+                "think": {
+                    "config": {
+                        "cors": "src/config.php"
+                    },
+                    "services": [
+                        "think\\cors\\Service"
+                    ]
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "think\\cors\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "yunwuxin",
+                    "email": "448901948@qq.com"
+                }
+            ],
+            "description": "The Cors Library For ThinkPHP",
+            "support": {
+                "issues": "https://github.com/top-think/think-cors/issues",
+                "source": "https://github.com/top-think/think-cors/tree/v1.0.2"
+            },
+            "install-path": "../topthink/think-cors"
+        },
         {
             "name": "topthink/think-filesystem",
             "version": "v2.0.3",

+ 15 - 6
vendor/composer/installed.php

@@ -1,11 +1,11 @@
 <?php return array(
     'root' => array(
-        'pretty_version' => '1.0.0+no-version-set',
-        'version' => '1.0.0.0',
+        'pretty_version' => 'dev-master',
+        'version' => 'dev-master',
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
-        'reference' => NULL,
+        'reference' => '23ea46551d04a04801572b25ee7958a879de42ab',
         'name' => 'topthink/think',
         'dev' => true,
     ),
@@ -218,12 +218,12 @@
             'dev_requirement' => false,
         ),
         'topthink/think' => array(
-            'pretty_version' => '1.0.0+no-version-set',
-            'version' => '1.0.0.0',
+            'pretty_version' => 'dev-master',
+            'version' => 'dev-master',
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
-            'reference' => NULL,
+            'reference' => '23ea46551d04a04801572b25ee7958a879de42ab',
             'dev_requirement' => false,
         ),
         'topthink/think-annotation' => array(
@@ -253,6 +253,15 @@
             'reference' => 'a24d442a02fb2a4716de232ff1a4f006c178a370',
             'dev_requirement' => false,
         ),
+        'topthink/think-cors' => array(
+            'pretty_version' => 'v1.0.2',
+            'version' => '1.0.2.0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../topthink/think-cors',
+            'aliases' => array(),
+            'reference' => '822d90b357daa5aa5e1d01668615599f428ad132',
+            'dev_requirement' => false,
+        ),
         'topthink/think-filesystem' => array(
             'pretty_version' => 'v2.0.3',
             'version' => '2.0.3.0',

+ 3 - 2
vendor/services.php

@@ -1,8 +1,9 @@
 <?php 
-// This file is automatically generated at:2025-06-24 11:50:29
+// This file is automatically generated at:2025-06-25 19:30:18
 declare (strict_types = 1);
 return array (
   0 => 'think\\annotation\\Service',
   1 => 'think\\captcha\\CaptchaService',
-  2 => 'think\\app\\Service',
+  2 => 'think\\cors\\Service',
+  3 => 'think\\app\\Service',
 );

+ 3 - 0
vendor/topthink/think-cors/.gitignore

@@ -0,0 +1,3 @@
+.idea
+composer.lock
+vendor

+ 127 - 0
vendor/topthink/think-cors/README.md

@@ -0,0 +1,127 @@
+# ThinkCors
+
+ThinkPHP跨域扩展
+
+## 安装
+
+```
+composer require topthink/think-cors
+```
+
+## 配置
+
+配置文件位于 `config/cors.php`
+
+```
+[
+    'paths' => ['api/*'],
+    ...
+]
+```
+
+### paths 配置示例
+
+允许 api 目录下的跨域请求,`*` 代表通配符。
+
+```php
+[
+    'paths' => ['api/*']
+]
+```
+
+当项目有多个域名时,支持为不同域名配置不同的目录。
+
+```php
+[
+    'paths' => [
+        'www.thinkphp.cn' => ['api/*'],
+        'doc.thinkphp.cn' => ['user/*', 'article/*'],
+    ]
+]
+```
+
+### allowed_origins 配置示例
+
+当配置中有 `*` 时,代表不限制来源域。
+
+```php
+[
+    'allowed_origins' => ['*'],
+]
+```
+
+当我们需要限制来源域时,可以这么写。
+
+```php
+[
+    'allowed_origins' => ['www.thinkphp.cn', 'm.thinkphp.cn'],
+]
+```
+
+### allowed_origins_patterns 配置示例
+
+除了固定来源域,有时候我们还想要允许不固定但有规则的来源域,那么可以通过正则来实现。例如这里我们允许 `thinkphp.cn` 的所有二级域。
+
+```php
+[
+    'allowed_origins_patterns' => ['#.*\.thinkphp\.cn#'],
+]
+```
+
+### allowed_methods 配置示例
+
+当配置中有 `*` 时,代表不限制来源请求方式。
+
+```php
+[
+    'allowed_methods' => ['*'],
+]
+```
+
+当然我们也可以限制只允许 `GET` 和 `POST` 的跨域请求。
+
+```php
+[
+    'allowed_methods' => ['GET', 'POST'],
+]
+```
+
+### allowed_headers 配置示例
+
+当配置中有 `*` 时,代表不限制请求头。
+
+```php
+[
+    'allowed_headers' => ['*'],
+]
+```
+
+当然我们也可以只允许跨域请求只传递给我们部分请求头。
+
+```php
+[
+    'allowed_headers' => ['X-Custom-Header', 'Upgrade-Insecure-Requests'],
+]
+```
+
+### max_age 配置示例
+
+跨域预检结果是有缓存的,如果值为 -1,表示禁用缓存,则每次请求前都需要使用 `OPTIONS` 预检请求。如果想减少 `OPTIONS` 预检请求,我们可以把缓存有效期设置长些。
+列如这里,我们把有效期设置为 2 小时(7200 秒):
+
+```php
+[
+    'max_age' => 7200,
+]
+```
+
+### supports_credentials 配置示例
+
+`Credentials` 可以是 `cookies`、`authorization headers` 或 `TLS client certificates`。当接口需要这些信息时,开启该项配置后,相关请求将会携带 `Credentials` 信息(如果有的话)。
+
+```php
+[
+    'supports_credentials' => true,
+]
+```
+

+ 29 - 0
vendor/topthink/think-cors/composer.json

@@ -0,0 +1,29 @@
+{
+    "name": "topthink/think-cors",
+    "description": "The Cors Library For ThinkPHP",
+    "license": "Apache-2.0",
+    "authors": [
+        {
+            "name": "yunwuxin",
+            "email": "448901948@qq.com"
+        }
+    ],
+    "require": {
+        "topthink/framework": "^6.0|^8.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "think\\cors\\": "src"
+        }
+    },
+    "extra": {
+        "think": {
+            "services": [
+                "think\\cors\\Service"
+            ],
+            "config": {
+                "cors": "src/config.php"
+            }
+        }
+    }
+}

+ 255 - 0
vendor/topthink/think-cors/src/HandleCors.php

@@ -0,0 +1,255 @@
+<?php
+
+namespace think\cors;
+
+use Closure;
+use think\Config;
+use think\Request;
+use think\Response;
+
+class HandleCors
+{
+    /** @var string[] */
+    protected $paths = [];
+    /** @var string[] */
+    protected $allowedOrigins = [];
+    /** @var string[] */
+    protected $allowedOriginsPatterns = [];
+    /** @var string[] */
+    protected $allowedMethods = [];
+    /** @var string[] */
+    protected $allowedHeaders = [];
+    /** @var string[] */
+    private $exposedHeaders      = [];
+    protected $supportsCredentials = false;
+    protected $maxAge              = 0;
+
+    protected $allowAllOrigins = false;
+    protected $allowAllMethods = false;
+    protected $allowAllHeaders = false;
+
+    public function __construct(Config $config)
+    {
+        $options = $config->get('cors', []);
+
+        $this->paths                  = $options['paths'] ?? $this->paths;
+        $this->allowedOrigins         = $options['allowed_origins'] ?? $this->allowedOrigins;
+        $this->allowedOriginsPatterns = $options['allowed_origins_patterns'] ?? $this->allowedOriginsPatterns;
+        $this->allowedMethods         = $options['allowed_methods'] ?? $this->allowedMethods;
+        $this->allowedHeaders         = $options['allowed_headers'] ?? $this->allowedHeaders;
+        $this->exposedHeaders         = $options['exposed_headers'] ?? $this->exposedHeaders;
+        $this->supportsCredentials    = $options['supports_credentials'] ?? $this->supportsCredentials;
+
+        $maxAge = $this->maxAge;
+        if (array_key_exists('max_age', $options)) {
+            $maxAge = $options['max_age'];
+        }
+        $this->maxAge = $maxAge === null ? null : (int) $maxAge;
+
+        // Normalize case
+        $this->allowedHeaders = array_map('strtolower', $this->allowedHeaders);
+        $this->allowedMethods = array_map('strtoupper', $this->allowedMethods);
+
+        // Normalize ['*'] to true
+        $this->allowAllOrigins = in_array('*', $this->allowedOrigins);
+        $this->allowAllHeaders = in_array('*', $this->allowedHeaders);
+        $this->allowAllMethods = in_array('*', $this->allowedMethods);
+
+        // Transform wildcard pattern
+        if (!$this->allowAllOrigins) {
+            foreach ($this->allowedOrigins as $origin) {
+                if (strpos($origin, '*') !== false) {
+                    $this->allowedOriginsPatterns[] = $this->convertWildcardToPattern($origin);
+                }
+            }
+        }
+    }
+
+    /**
+     * @param Request $request
+     * @param Closure $next
+     * @return Response
+     */
+    public function handle($request, Closure $next)
+    {
+        if (!$this->hasMatchingPath($request)) {
+            return $next($request);
+        }
+
+        if ($this->isPreflightRequest($request)) {
+            return $this->handlePreflightRequest($request);
+        }
+
+        /** @var Response $response */
+        $response = $next($request);
+
+        return $this->addPreflightRequestHeaders($response, $request);
+    }
+
+    protected function addPreflightRequestHeaders(Response $response, Request $request): Response
+    {
+        $this->configureAllowedOrigin($response, $request);
+
+        if ($response->getHeader('Access-Control-Allow-Origin')) {
+            $this->configureAllowCredentials($response, $request);
+            $this->configureAllowedMethods($response, $request);
+            $this->configureAllowedHeaders($response, $request);
+            $this->configureExposedHeaders($response, $request);            
+            $this->configureMaxAge($response, $request);
+        }
+
+        return $response;
+    }
+
+    protected function configureAllowedOrigin(Response $response, Request $request): void
+    {
+        if ($this->allowAllOrigins === true && !$this->supportsCredentials) {
+            $response->header(['Access-Control-Allow-Origin' => '*']);
+        } elseif ($this->isSingleOriginAllowed()) {
+            $response->header(['Access-Control-Allow-Origin' => array_values($this->allowedOrigins)[0]]);
+        } else {
+            if ($this->isCorsRequest($request) && $this->isOriginAllowed($request)) {
+                $response->header(['Access-Control-Allow-Origin' => (string) $request->header('Origin')]);
+            }
+        }
+    }
+
+    protected function configureAllowCredentials(Response $response, Request $request): void
+    {
+        if ($this->supportsCredentials) {
+            $response->header(['Access-Control-Allow-Credentials' => 'true']);
+        }
+    }
+
+    protected function configureAllowedMethods(Response $response, Request $request): void
+    {
+        if ($this->allowAllMethods === true) {
+            $allowMethods = strtoupper((string) $request->header('Access-Control-Request-Method'));
+        } else {
+            $allowMethods = implode(', ', $this->allowedMethods);
+        }
+
+        $response->header(['Access-Control-Allow-Methods' => $allowMethods]);
+    }
+
+    protected function configureAllowedHeaders(Response $response, Request $request): void
+    {
+        if ($this->allowAllHeaders === true) {
+            $allowHeaders = (string) $request->header('Access-Control-Request-Headers');
+        } else {
+            $allowHeaders = implode(', ', $this->allowedHeaders);
+        }
+        $response->header(['Access-Control-Allow-Headers' => $allowHeaders]);
+    }
+
+    protected function configureExposedHeaders(Response $response, Request $request): void
+    {
+        if ($this->exposedHeaders) {
+            $exposeHeaders = implode(', ', $this->exposedHeaders);
+            $response->header(['Access-Control-Expose-Headers' => $exposeHeaders]);
+        }
+    }
+
+    protected function configureMaxAge(Response $response, Request $request): void
+    {
+        if ($this->maxAge !== null) {
+            $response->header(['Access-Control-Max-Age' => (string) $this->maxAge]);
+        }
+    }
+
+    protected function handlePreflightRequest(Request $request)
+    {
+        $response = response('', 204);
+
+        return $this->addPreflightRequestHeaders($response, $request);
+    }
+
+    protected function isCorsRequest(Request $request)
+    {
+        return !!$request->header('Origin');
+    }
+
+    protected function isPreflightRequest(Request $request)
+    {
+        return $request->method() === 'OPTIONS' && $request->header('Access-Control-Request-Method');
+    }
+
+    protected function isSingleOriginAllowed(): bool
+    {
+        if ($this->allowAllOrigins === true || count($this->allowedOriginsPatterns) > 0) {
+            return false;
+        }
+
+        return count($this->allowedOrigins) === 1;
+    }
+
+    protected function isOriginAllowed(Request $request): bool
+    {
+        if ($this->allowAllOrigins === true) {
+            return true;
+        }
+
+        $origin = (string) $request->header('Origin');
+
+        if (in_array($origin, $this->allowedOrigins)) {
+            return true;
+        }
+
+        foreach ($this->allowedOriginsPatterns as $pattern) {
+            if (preg_match($pattern, $origin)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    protected function hasMatchingPath(Request $request)
+    {
+        $url = $request->pathInfo();
+        $url = trim($url, '/');
+        if ($url === '') {
+            $url = '/';
+        }
+
+        $paths = $this->getPathsByHost($request->host(true));
+
+        foreach ($paths as $path) {
+            if ($path !== '/') {
+                $path = trim($path, '/');
+            }
+
+            if ($path === $url) {
+                return true;
+            }
+
+            $pattern = $this->convertWildcardToPattern($path);
+
+            if (preg_match($pattern, $url) === 1) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    protected function getPathsByHost($host)
+    {
+        $paths = $this->paths;
+
+        if (isset($paths[$host])) {
+            return $paths[$host];
+        }
+
+        return array_filter($paths, function ($path) {
+            return is_string($path);
+        });
+    }
+
+    protected function convertWildcardToPattern($pattern)
+    {
+        $pattern = preg_quote($pattern, '#');
+        $pattern = str_replace('\*', '.*', $pattern);
+        return '#^' . $pattern . '\z#u';
+    }
+}

+ 13 - 0
vendor/topthink/think-cors/src/Service.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace think\cors;
+
+class Service extends \think\Service
+{
+    public function boot(): void
+    {
+        $this->app->event->listen('HttpRun', function () {
+            $this->app->middleware->add(HandleCors::class);
+        });
+    }
+}

+ 12 - 0
vendor/topthink/think-cors/src/config.php

@@ -0,0 +1,12 @@
+<?php
+
+return [
+    'paths'                    => [],
+    'allowed_origins'          => ['*'],
+    'allowed_origins_patterns' => [],
+    'allowed_methods'          => ['*'],
+    'allowed_headers'          => ['*'],
+    'exposed_headers'          => [],
+    'max_age'                  => 0,
+    'supports_credentials'     => false,
+];