【问题标题】:Error in Laravel Handler error context with Auth使用 Auth 的 Laravel 处理程序错误上下文中的错误
【发布时间】:2018-05-14 05:10:21
【问题描述】:

经过一番调查,我发现了以下内容:

当用户使用错误的 Bearer 向我们的 API 发出请求时,会抛出 OAuthServerException 并且 Handler 类的 report 方法是调用以查找要添加到报告信息的上下文。在 context 方法期间,调用了 Auth 外观,这是它双重失败的地方,并调用了粗暴的 503 错误。

为了隐藏问题,我在 $dontreport 属性中添加了 OAuthServerException::class,但这并不能解决问题,它不应该被隐藏...

您能否帮我弄清楚为什么在抛出 OAuthServerException 时 Auth 门面会失败?

编辑:为了添加一些“上下文”,我发现这个错误报告和相关的 PR 看起来像我的问题,但没有谈论 Auth 门面...... https://github.com/laravel/framework/issues/21041 但也许它是链接的。

Edit2:用户按预期扩展了 Laravel 的 Auth\User:

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Auth;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use ModelTrait, HasApiTokens, Notifiable;

    /* some methods */
}

Edit3:添加 Handler 类

namespace App\Exceptions;

use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Foundation\Testing\HttpException;
use League\OAuth2\Server\Exception\OAuthServerException;
use Symfony\Component\HttpFoundation\Response;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        \Illuminate\Auth\AuthenticationException::class,
        \Illuminate\Auth\Access\AuthorizationException::class,
        \Symfony\Component\HttpKernel\Exception\HttpException::class,
        \Illuminate\Database\Eloquent\ModelNotFoundException::class,
        \Illuminate\Session\TokenMismatchException::class,
        \Illuminate\Validation\ValidationException::class,
        OAuthServerException::class // This is just a temporary fix 
    ];

    /**
     * Report or log an exception.
     *
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
     *
     * @param  \Exception $exception
     * @return void
     */
    public function report(Exception $exception)
    {
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Exception $exception
     * @return \Illuminate\Http\Response|Response
     */
    public function render($request, Exception $exception)
    {
        if ($exception instanceof HttpException) {
            return response()->json(
                ['error' => $exception->getMessage()],
                $exception->getCode()
            );
        }
        if ($request->wantsJson()) {
            $response = [
                'errors' => 'Sorry, something went wrong.'
            ];
            $response['message'] = $exception->getMessage();
            if (get_class($exception) == 'Illuminate\Validation\ValidationException') {
                $response['rules'] = $exception->validator->errors();
            }
            if (config('app.debug')) {
                // Add the exception class name, message and stack trace to response
                $response['exception'] = get_class($exception); // Reflection might be better here

                $response['trace'] = $exception->getTrace();
            }
            // Default response of 400
            $status = 400;
            // If this exception is an instance of HttpException
            if ($this->isHttpException($exception)) {
                // Grab the HTTP status code from the Exception
                $status = $exception->getStatusCode();
            }
            // Return a JSON response with the response array and status code
            return response()->json($response, $status);
        }
        return parent::render($request, $exception);
    }

    /**
     * Convert an authentication exception into an unauthenticated response.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Illuminate\Auth\AuthenticationException $exception
     * @return \Illuminate\Http\Response
     */
    protected function unauthenticated($request, AuthenticationException $exception)
    {
        if ($request->expectsJson()) {
            return response()->json(['error' => 'Unauthenticated.'], 401);
        }

        return redirect()->guest(route('login'));
    }
}

这两个函数来自 Laravel\Illuminate\Foundation\Exceptions\Handler(我的 Handler 类的父类),调用 Auth 时,503 发生在上下文方法中。

/**
     * Report or log an exception.
     *
     * @param  \Exception  $e
     * @return mixed
     *
     * @throws \Exception
     */
    public function report(Exception $e)
    {
        if ($this->shouldntReport($e)) {
            return;
        }

        if (method_exists($e, 'report')) {
            return $e->report();
        }

        try {
            $logger = $this->container->make(LoggerInterface::class);
        } catch (Exception $ex) {
            throw $e; // throw the original exception
        }
        $logger->error(
            $e->getMessage(),
            array_merge($this->context(), ['exception' => $e]
        ));
    }

    /**
     * Get the default context variables for logging.
     *
     * @return array
     */
    protected function context()
    {

        try {
            return array_filter([
                'userId' => Auth::id(),
                'email' => Auth::user() ? Auth::user()->email : null,
            ]);
        } catch (Throwable $e) {
            return [];
        }
    }

【问题讨论】:

  • 您可能需要添加一些 sn-ps 代码来帮助查看到底发生了什么。我假设您正在使用它的 Passport。你的中间件是什么样的?任何其他与规范不同的配置?
  • @Paul Handler 类是 Laravel 中直接开箱即用的类,对于 Passport 也是一样...
  • 我们需要 sn-ps 来帮助你@Paul
  • @PaulSantos 我已经添加了处理程序类,但我真的不知道要提供什么代码 sn-p。中间件,它也是来自 Laravel Passport 的,没什么新鲜的。
  • @Roadirsh,您是否更新了 config/auth.php 以使用模型的正确命名空间?

标签: php laravel exception php-7 laravel-5.5


【解决方案1】:

如您所说,在报告异常时会调用 Auth:: 方法,这反过来又会引发另一个相同类型的异常。

如果您不想 dontReport 这个异常,您可以改写 context 方法并让它只返回 []

但是,不报告 OAuthServerException 可能确实有意义。查看基本异常处理程序如何不报告Illuminate\Auth\AuthenticationExceptionIlluminate\Auth\Access\AuthorizationException。这将是您未报告的另一个与身份验证相关的异常。

【讨论】:

  • 是的,但是为什么 Throwable 类没有捕获到这个异常?这就是它的目的,如果 Auth 失败,则返回一个空数组。我不应该需要覆盖它...
  • @Roadirsh 我认为它被捕获了earlier in the process,这就是为什么你看到的错误不是抛出异常,而是一个循环(OAuthServerException -> report -> context -> OAuthServerException -> report...
  • 第一次被抓到in the token guard 但是为什么Auth失败。当我调用未经过身份验证的 Auth::id() 时,它应该只返回 null,而不是异常。 Auth::check() 也一样。实例化 Auth 外观时出现 503 错误。对我来说这不是同一个例外,所以没有循环......
  • @Roadirsh 哦,好的,我会尝试重现此内容并稍后回复您
猜你喜欢
  • 2015-03-29
  • 2018-03-02
  • 1970-01-01
  • 1970-01-01
  • 2016-08-18
  • 1970-01-01
  • 2012-10-13
  • 2019-10-27
  • 2011-10-10
相关资源
最近更新 更多