【问题标题】:Return JsonResponse when i use an AuthTokenAuthenticator (symfony 3)当我使用 AuthTokenAuthenticator (symfony 3) 时返回 JsonResponse
【发布时间】:2018-11-04 10:44:23
【问题描述】:

我指定我从 Symfony 开始。我想创建一个带有令牌的 API(没有 FOSRestBundle)作为身份验证手段。

我按照不同的教程进行此设置。我想要的是当“AuthTokenAuthenticator”类发现错误时,它返回一个json而不是html视图。

这是我的脚本:

AuthTokenAuthenticator

namespace AppBundle\Security;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\SimplePreAuthenticatorInterface;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\HttpFoundation\JsonResponse;

class AuthTokenAuthenticator implements 
SimplePreAuthenticatorInterface, AuthenticationFailureHandlerInterface
{

const TOKEN_VALIDITY_DURATION = 12 * 3600;

protected $httpUtils;

public function __construct(HttpUtils $httpUtils)
{
    $this->httpUtils = $httpUtils;
}

public function createToken(Request $request, $providerKey)
{

    //$targetUrlToken = '/auth-tokens'; // login
    //$targetUrlUser = '/users/create'; // create account

    /*if ($request->getMethod() === "POST" && $this->httpUtils->checkRequestPath($request, $targetUrlUser) || $request->getMethod() === "POST" && $this->httpUtils->checkRequestPath($request, $targetUrlToken) ) {
        return;
    }*/

    $authTokenHeader = $request->headers->get('X-Auth-Token');

    if (!$authTokenHeader) {
        //return new JsonResponse(array("error" => 1, "desc" => "INVALID_TOKEN", "message" => "X-Auth-Token header is required"));
       throw new BadCredentialsException('X-Auth-Token header is required');


    }

    return new PreAuthenticatedToken(
        'anon.',
        $authTokenHeader,
        $providerKey
        );
}

public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
{
    if (!$userProvider instanceof AuthTokenUserProvider) {
        throw new \InvalidArgumentException(
            sprintf(
                'The user provider must be an instance of AuthTokenUserProvider (%s was given).',
                get_class($userProvider)
                )
            );
    }

    $authTokenHeader = $token->getCredentials();
    $authToken = $userProvider->getAuthToken($authTokenHeader);

    if (!$authToken || !$this->isTokenValid($authToken)) {
        throw new BadCredentialsException('Invalid authentication token');
    }

    $user = $authToken->getUser();
    $pre = new PreAuthenticatedToken(
        $user,
        $authTokenHeader,
        $providerKey,
        $user->getRoles()
        );

    $pre->setAuthenticated(true);

    return $pre;
}

public function supportsToken(TokenInterface $token, $providerKey)
{
    return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
}

/**
 * Vérifie la validité du token
 */
private function isTokenValid($authToken)
{
    return (time() - $authToken->getCreatedAt()->getTimestamp()) < self::TOKEN_VALIDITY_DURATION;
}

public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{

    throw $exception;
}
}

这是我没有通知令牌时的错误返回:

<!DOCTYPE html>
<html>
<head>
<title>    X-Auth-Token header is required (500 Internal Server Error)

如何获得返回的 json 响应? 如果我尝试执行 return new JsonResponse(array("test" => "KO")) (简单示例),我会收到此错误:

<title>    Type error: Argument 1 passed to Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager::authenticate() must be an instance of Symfony\Component\Security\Core\Authentication\Token\TokenInterface, instance of Symfony\Component\HttpFoundation\JsonResponse given, called in /Users/mickaelmercier/Desktop/workspace/api_monblocrecettes/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php on line 101 (500 Internal Server Error)

【问题讨论】:

  • 请把介绍翻译成英文。
  • 您是否尝试在路由定义中强制使用 json 格式?

标签: json api symfony token


【解决方案1】:

您可以创建自己的错误处理程序。它是一个监听kernel.exception的事件监听器或订阅者,当它对事件添加响应时,事件传播停止,因此不会触发默认的错误处理程序。

它可能看起来像这样:

<?php declare(strict_types = 1);

namespace App\EventSubsbscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\KernelEvents;

final class ExceptionToJsonResponseSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::EXCEPTION => 'onKernelException',
        ];
    }

    public function onKernelException(GetResponseForExceptionEvent $event): void
    {
        // Skip if request is not an API-request
        $request = $event->getRequest();
        if (strpos($request->getPathInfo(), '/api/') !== 0) {
            return;
        }
        $exception = $event->getException();
        $error = [
            'type' => $this->getErrorTypeFromException($exception),
            // Warning! Passing the exception message without checks is insecure.
            // This will potentially leak sensitive information.
            // Do not use this in production!
            'message' => $exception->getMessage(),
        ];
        $response = new JsonResponse($error, $this->getStatusCodeFromException($exception));
        $event->setResponse($response);
    }

    private function getStatusCodeFromException(\Throwable $exception): int
    {
        if ($exception instanceof HttpException) {
            return $exception->getStatusCode();
        }

        return 500;
    }

    private function getErrorTypeFromException(\Throwable $exception): string
    {
        $parts = explode('\\', get_class($exception));

        return end($parts);
    }
}

ApiPlatform 提供了自己的异常侦听器,更高级,如果您需要“更好”的异常响应,可以查看它。

【讨论】:

  • 真的很棒!其作品 !我需要了解有关异常侦听器的更多信息。谢谢
猜你喜欢
  • 2019-01-07
  • 1970-01-01
  • 1970-01-01
  • 2015-04-11
  • 1970-01-01
  • 2014-10-16
  • 1970-01-01
  • 2021-03-19
  • 2017-12-24
相关资源
最近更新 更多