You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 10项目如何限制API接口仅内部访问,禁止外部公开访问?

最佳实现方案

针对你的需求,核心思路是确保API请求仅来自应用内部的视图/React组件,拦截外部直接访问。以下是几种可靠的实现方式,按推荐优先级排序:

1. 迁移API路由到web.php,复用Laravel自带的CSRF与会话保护

这是最简单高效的方案,利用Laravel web 中间件组的内置安全机制:

步骤:

  • 将需要保护的API路由从 api.php 迁移到 web.php,比如:

    // web.php
    use App\Http\Controllers\ProductController;
    
    Route::get('/api/product/{id}', [ProductController::class, 'show']);
    

    (web 中间件组默认已包含CSRF保护、会话管理,无需额外添加)

  • 在Blade视图中把CSRF令牌注入全局变量,供React使用:

    <script>
        window.csrfToken = '{{ csrf_token() }}';
    </script>
    <div id="react-app"></div>
    
  • 配置Axios自动携带CSRF令牌和AJAX标识头:

    import axios from 'axios';
    
    // 全局配置
    axios.defaults.headers.common = {
        'X-CSRF-TOKEN': window.csrfToken,
        'X-Requested-With': 'XMLHttpRequest'
    };
    
    // 发起请求示例
    axios.get('/api/product/1')
        .then(res => console.log(res.data));
    
  • 可选:添加AJAX请求检查(拦截地址栏直接访问)
    创建一个简单的中间件验证请求是否为AJAX:

    php artisan make:middleware OnlyAjax
    

    中间件逻辑:

    <?php
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    
    class OnlyAjax
    {
        public function handle(Request $request, Closure $next)
        {
            if (!$request->ajax()) {
                return response()->json(['message' => '未授权访问'], 401);
            }
            return $next($request);
        }
    }
    

    注册中间件后,给路由添加:

    Route::get('/api/product/{id}', [ProductController::class, 'show'])->middleware('only.ajax');
    

优势:

  • 复用Laravel原生安全机制,无需从零构建验证逻辑
  • 会话与CSRF令牌绑定,外部请求无法伪造有效凭证
  • 实现成本极低,代码改动少

2. 自定义中间件验证内部请求(适合保留api.php路由的场景)

如果不想迁移路由,可以给api路由添加自定义中间件,验证请求是否来自内部:

步骤:

  • 创建自定义中间件:

    php artisan make:middleware InternalApiAccess
    
  • 编写中间件逻辑(结合会话、CSRF、AJAX检查):

    <?php
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Session;
    
    class InternalApiAccess
    {
        public function handle(Request $request, Closure $next)
        {
            // 验证会话存在且CSRF令牌匹配
            if (!Session::exists('_token') || !$request->hasHeader('X-CSRF-TOKEN') || $request->header('X-CSRF-TOKEN') !== csrf_token()) {
                return response()->json(['message' => '未授权访问'], 401);
            }
    
            // 验证是AJAX请求(拦截地址栏直接访问)
            if (!$request->ajax()) {
                return response()->json(['message' => '未授权访问'], 401);
            }
    
            return $next($request);
        }
    }
    
  • 在 app/Http/Kernel.php 注册中间件:

    protected $routeMiddleware = [
        // ...
        'internal.api' => \App\Http\Middleware\InternalApiAccess::class,
    ];
    
  • 给需要保护的api路由添加中间件:

    // api.php
    Route::get('/product/{id}', [ProductController::class, 'show'])->middleware('internal.api');
    
  • 后续步骤同方案1:Blade注入CSRF令牌,Axios配置携带头


额外防护建议

为了进一步防止批量爬取,可以添加以下辅助措施:

  • 请求频率限制:给路由添加Laravel自带的 throttle 中间件,比如 ->middleware('throttle:10,1')(每分钟最多10次请求)
  • Referer校验(辅助):在中间件中添加Referer头检查,确认请求来源是自身域名(注意:Referer可伪造,仅作为补充验证)
    $referer = parse_url($request->headers->get('Referer') ?? '');
    if (!isset($referer['host']) || $referer['host'] !== parse_url(config('app.url'))['host']) {
        return response()->json(['message' => '未授权访问'], 401);
    }
    

内容的提问来源于stack exchange,提问作者rfadeout

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 20:05:07