【问题标题】:Custom Middleware Not working when using Sanctum使用 Sanctum 时自定义中间件不起作用
【发布时间】:2021-08-27 10:28:30
【问题描述】:

我正在为我的 laravel API 项目使用动态数据库。我正在使用中间件来做到这一点。当我在 api rout 中间件中使用 auth:sanctum 时不起作用。但通常它工作正常。

路由>api.php

Route::group(['middleware'=>'database'], function() {
    Route::group(['namespace' => 'App\Http\Controllers\Admin', 'middleware' => ['auth:sanctum']], function () {
        Route::get('dashboard', function () {
            return "conncted sucessfully to database ".\DB::connection()->getDatabaseName();
        });
    });
});

中间件 > Database.php

namespace App\Http\Middleware;

use Closure;
use App\Models\SoftClient;

class Database
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $route = app('router')->getRoutes()->match($request);
        $prefix = $route->action['name'];

        $s_client = SoftClient::where('url', $prefix)->first();
        \Config::set('database.connections.multidomain.host', $s_client->db_host );
        \Config::set('database.connections.multidomain.database', $s_client->db_name );
        \Config::set('database.connections.multidomain.username', $s_client->db_username );
        \Config::set('database.connections.multidomain.password', $s_client->db_password );

        \DB::reconnect('multidomain');

        return $next($request);
    }
}

'database' => \App\Http\Middleware\Database::class,

我将这个添加到 Karnel.php

当我向仪表板发送请求时,出现以下错误。如果我不使用auth:sanctum,它工作正常。

Illuminate\Database\QueryException: SQLSTATE[HY000] [1045] Access denied for user ''@'localhost' (using password: NO)

【问题讨论】:

    标签: laravel laravel-api


    【解决方案1】:

    auth sanctum 用于对用户进行身份验证。也许您正在使用身份验证用户直接访问路由。

    【讨论】:

      【解决方案2】:

      当你用“php artisan route:list”检查路由时,你看到你用路由配置的中间件了吗? 我有一个类似的问题,其中 route:list 指出我用组定义的中间件实际上并没有使用,最后我删除了“组”并单独定义了路由。有点麻烦,但确实有效。

      【讨论】:

      • 考虑在您的答案中添加上下文,以帮助使其更加“独立”。有时,答案的链接方式使读者不一定会看到问题本身。
      【解决方案3】:

      如果您的目标是使用 laravel sanctum 进行动态数据库连接,那么我使用此方法并且它有效

      第一步:复制这个文件 Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful 到我们的中间件,然后像这样修改复制这个文件

      <?php
      
      namespace App\Http\Middleware;
      
      use Illuminate\Routing\Pipeline;
      use Illuminate\Support\Collection;
      use Illuminate\Support\Str;
      use Illuminate\Support\Facades\Config;
      use Illuminate\Support\Facades\App;
      
      class EnsureFrontendRequestsAreStateful
      {
          /**
           * Handle the incoming requests.
           *
           * @param  \Illuminate\Http\Request  $request
           * @param  callable  $next
           * @return \Illuminate\Http\Response
           */
          public function handle($request, $next)
          {
              $this->changeDatabaseConnection($request);
              $this->configureSecureCookieSessions();
      
              return (new Pipeline(app()))->send($request)->through(static::fromFrontend($request) ? [
                  function ($request, $next) {
                      $request->attributes->set('sanctum', true);
      
                      return $next($request);
                  },
                  config('sanctum.middleware.encrypt_cookies', \Illuminate\Cookie\Middleware\EncryptCookies::class),
                  \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
                  \Illuminate\Session\Middleware\StartSession::class,
                  config('sanctum.middleware.verify_csrf_token', \Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class),
              ] : [])->then(function ($request) use ($next) {
                  return $next($request);
              });
          }
      
          protected function changeDatabaseConnection($request)
          {
              $encodeCc   = $request->input('cc');
              $cc         = json_decode(base64_decode($encodeCc));
      
              if ((!empty($cc) && $cc != 'axiasolusi')) {
                  $compCode = $cc;
      
                  if (App::environment() === 'local') {
                      $compCode = 'ess-' . $compCode;
                  }
              } else {
                  $compCode = env('DB_DATABASE');
              }
      
              Config::set('database.connections.' . env("DB_CONNECTION") . '.database', $compCode);
          }
      
          /**
           * Configure secure cookie sessions.
           *
           * @return void
           */
          protected function configureSecureCookieSessions()
          {
              config([
                  'session.http_only' => true,
                  'session.same_site' => 'lax',
              ]);
          }
      
          /**
           * Determine if the given request is from the first-party application frontend.
           *
           * @param  \Illuminate\Http\Request  $request
           * @return bool
           */
          public static function fromFrontend($request)
          {
              $domain = $request->headers->get('referer') ?: $request->headers->get('origin');
      
              if (is_null($domain)) {
                  return false;
              }
      
              $domain = Str::replaceFirst('https://', '', $domain);
              $domain = Str::replaceFirst('http://', '', $domain);
              $domain = Str::endsWith($domain, '/') ? $domain : "{$domain}/";
      
              $stateful = array_filter(config('sanctum.stateful', []));
      
              return Str::is(Collection::make($stateful)->map(function ($uri) {
                  return trim($uri) . '/*';
              })->all(), $domain);
          }
      }
      

      第 2 步:像这样更改 karnel

      'api' => [
                  // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, // original
                  \App\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
                  'throttle:api',
                  \Illuminate\Routing\Middleware\SubstituteBindings::class,
              ],
      

      最后一步:更改路由 api

      Route::middleware('change.database')->group(function () {
      
                      Route::post('/verify-company-code', 'Api\Web\Auth@verifyCompanyCode');
                      Route::post('/verify-user-account', 'Api\Web\Auth@verifyUserAccount');
                      Route::post('/verify-user-pin', 'Api\Web\Auth@verifyUserPin');
                      Route::post('/forgot-password', 'Api\Web\Auth@forgotPassword');
                      Route::post('/reset-password', 'Api\Web\Auth@resetPassword');
                  });
      
                  Route::middleware(['auth:sanctum'])->group(function () {
      
                      Route::post('logout', [Auth::class, 'logout']);
                      Route::post('logout-all', 'Api\Web\Auth@logoutAll');
                  });
              });
      

      【讨论】:

      • 请注意,如果您不想更改数据库名称而只想添加新连接,那么您必须在每个访问数据库的方法中设置默认连接
      • 不要只说“像这样改变[内核]”。确定您所做的更改。与EnsureFrontendRequestsAreStateful.php 相同,没有迹象表明您对原始版本进行了哪些更改。您甚至不应该从原始文件中复制和粘贴,只需扩展类并覆盖您需要更改的几个函数。
      • ok 谢谢先生 :)
      猜你喜欢
      • 1970-01-01
      • 2012-12-12
      • 2021-07-24
      • 2021-02-18
      • 2014-03-07
      • 1970-01-01
      • 2017-11-09
      • 1970-01-01
      • 2023-03-19
      相关资源
      最近更新 更多