【问题标题】:Security throwns 500 exception with Token was not found in TokenStorage instead of 403 or 401Security throws 500 exception with Token is not found in TokenStorage 而不是 403 或 401
【发布时间】:2016-03-26 11:24:39
【问题描述】:

我通过ApiKey 进行授权,如果没有提供授权数据,我想获得401 Unauthorized,如果授权数据无效,我想获得403 Forbidden。但我在这两种情况下都得到了500 Internal Server Error

security.yml

security:

    providers:
        api_key_user_provider:
            entity:
                class: RestBundle:RestUser
                property: apikey

    firewalls:
        rest_api_area:
            pattern: ^/api
            stateless: true
            rest_auth:
                header: x-apikey
            provider: api_key_user_provider

    access_control:
        - { path: ^/api, roles: ROLE_REST_USER }

RestUserListener.php

class RestUserListener implements ListenerInterface
{
    protected $tokenStorage;
    protected $authenticationManager;
    private $header;

    function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $header)
    {
        $this->tokenStorage = $tokenStorage;
        $this->authenticationManager = $authenticationManager;
        $this->header = $header;
    }

    public function handle(GetResponseEvent $event)
    {
        $request = $event->getRequest();

        $apikey = $request->headers->get($this->header);
        if (!$apikey) return;

        $token = new RestUserToken();
        $token->setUser($apikey);

        $authToken = $this->authenticationManager->authenticate($token);
        $this->tokenStorage->setToken($authToken);
        return;
    }
}

RestUserAuthenticationProvider.php:

class RestUserAuthenticationProvider implements AuthenticationProviderInterface
{
    private $userProvider;

    public function __construct(UserProviderInterface $userProvider)
    {
        $this->userProvider = $userProvider;
    }

    public function authenticate(TokenInterface $token)
    {
        $user = $this->userProvider->loadUserByUsername($token->getUsername());

        if ($user)
        {
            $authenticatedToken = new RestUserToken($user->getRoles());
            $authenticatedToken->setUser($user);

            return $authenticatedToken;
        }

        throw new AuthenticationException("Apikey not found.");
    }

    public function supports(TokenInterface $token)
    {
        return $token instanceof RestUserToken;
    }
}

RestUserToken就像AbstractToken一样简单,没有额外的逻辑。

api_key_user_provider是由RestUserapikey属性标识的标准实体提供者

RestUserFactory 里面也没有额外的魔法,就像官方文档中的一样

【问题讨论】:

    标签: php security symfony


    【解决方案1】:

    RestUserListener::handle() 方法应该处理返回 HTTP 401 或 HTTP 403 的情况。

    仅仅拥有return; 不会让这种情况发生。

    在我写的一个类似的应用程序中,我这样做了:

    use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
    
    //
    ...
    //
    
    public function handle(GetResponseEvent $event)
    {
        $request = $event->getRequest();
    
        if ( /* something invalid here, so error */ ) {
            $context = $request->getHost();
    
            throw new UnauthorizedHttpException(
                "Basic realm=\"$context\"",
                'Please authenticate correctly or any other message here'
            );
        }
    }
    

    抛出 UnauthorizedHttpException 将导致 HTTP 401(如果您查看异常的源代码就会明白)。

    对于 HTTP 403,您可以改用 Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException

    【讨论】:

    • 谢谢!真的很好的答案。我已经让hadle() 抛出AuthenticationException,在KernelExceptionListener 中转换为适当的HTTP 错误。
    • 是的,效果很好。但是如果我想在^/api 中再添加一种身份验证方法?您的解决方案将阻止所有其他身份验证方法,因为它会引发异常,并且没有给其他安全侦听器机会,不是吗?
    猜你喜欢
    • 2016-04-17
    • 2019-09-04
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 2023-01-14
    • 2015-08-16
    • 1970-01-01
    • 2023-03-13
    相关资源
    最近更新 更多