简体   繁体   English

如何从早期/自动加载的Symfony 3路由器生成绝对URL

[英]How to generate Absolute URL from Early/Auto loaded Symfony 3 router

I am writing Guards to handle OAuth for my Symfony 3 application. 我正在编写Guards来为我的Symfony 3应用程序处理OAuth。

As part of it, in one of my services, I need to generate an absolute URL to send to Twitter as the Callback URL. 作为其中一部分,在我的一项服务中,我需要生成一个绝对URL作为回调URL发送给Twitter。

#services.yml
...
app.twitter_client:
    class: MyApiBundle\Services\TwitterClient
    arguments:
        - %twitter_client_id%
        - %twitter_client_secret%
        - connect_twitter_check
        - '@request_stack'
        - '@router'
        - '@logger'
app.twitter_authenticator:
    class: MyApiBundle\Security\TwitterAuthenticator
    arguments:
        - '@app.twitter_client'
        - '@logger'

The logger is temporary for debugging. 记录器是用于调试的临时工具。

#TwitterClient.php service
...
use Monolog\Logger;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RouterInterface;
class TwitterClient
{

/**
 * TwitterClient constructor.
 * @param string          $identifier
 * @param string          $secret
 * @param string          $callbackUrl
 * @param RequestStack    $requestStack
 * @param RouterInterface $router
 * @param Logger          $logger
 */
public function __construct(
    string $identifier,
    string $secret,
    string $callbackUrl,
    RequestStack $requestStack,
    RouterInterface $router,
    Logger $logger
) {
    $callbackUrl = $router->generate($callbackUrl, [], RouterInterface::ABSOLUTE_URL);
    $logger->info($callbackUrl);
    ...
}

And when it outputs the $callbackUrl to the logs, it just says localhost, even though I am accessing it using a different URL. 并且当它向日志输出$callbackUrl ,即使我使用其他URL访问它,它也只是说localhost。

http://localhost/connect/twitter/check

But if I do the same from my a controller, it outputs the full proper URL. 但是,如果我从控制器执行相同的操作,它将输出完整的正确URL。

#TwitterController.php
...
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;


class TwitterController extends Controller
{
    /**
     * @Route("/connect/twitter")
     * @return RedirectResponse
     */
    public function connectAction()
    {
        /** @var RouterInterface $router */
        $router = $this->container->get('router');
        $callbackUrl = $router->generate('connect_twitter_check', [], RouterInterface::ABSOLUTE_URL);
        /** @var Logger $logger */
        $logger = $this->container->get('logger');
        $this->container->get('logger')
            ->info($callbackUrl);
        ...

This outputs: 输出:

https://dev.myapi.com:8082/app_dev.php/connect/twitter/check

The dev.myapi.com domain is set up in my hosts file and points to localhost, to make it easier to differentiate between my local apps and also to make it easier to integrate with OAuth services. 在我的主机文件中设置了dev.myapi.com域,它指向localhost,以便于区分本地应用程序并使其与OAuth服务集成更加容易。

I managed to solve this by setting the Router context. 我设法通过设置路由器上下文解决了这个问题。 I already loaded in the RequestStack to access the user's IP, so I used it to set the context of the Route and then the router worked as expected. 我已经加载了RequestStack来访问用户的IP,所以我用它来设置Route的上下文,然后路由器按预期工作。 I ran into problems trying to use the RequestStack in the constructor, so I ended up refactoring it so that it used the RequestStack as late as possible. 我在尝试在构造函数中使用RequestStack时遇到了问题 ,因此我最终对其进行了重构,以使其尽可能晚地使用RequestStack。

class TwitterClient
{
    private $identifier;
    private $secret;
    private $callbackUrl;
    private $requestStack;
    private $router;
    private $server;

    /**
     * TwitterClient constructor.
     *
     * @param string          $identifier
     * @param string          $secret
     * @param string          $callbackUrl
     * @param RequestStack    $requestStack
     * @param RouterInterface $router
     */
    public function __construct(
        string $identifier,
        string $secret,
        string $callbackUrl,
        RequestStack $requestStack,
        RouterInterface $router
    ) {
        $this->identifier = $identifier;
        $this->secret = $secret;
        $this->callbackUrl = $callbackUrl;
        $this->requestStack = $requestStack;
        $this->router = $router;
    }

    /**
     * Wait until the last moment to create the Twitter object to make sure that the requestStack is loaded.
     *
     * @return \League\OAuth1\Client\Server\Twitter
     */
    private function getServer()
    {
        if (!$this->server) {
            $context = new RequestContext();
            $context->fromRequest($this->requestStack->getCurrentRequest());
            $this->router->setContext($context);
            $callbackUrl = $this->router->generate($this->callbackUrl, [], RouterInterface::ABSOLUTE_URL);
            $this->server = new Twitter(
                [
                    'identifier' => $this->identifier,
                    'secret' => $this->secret,
                    'callback_uri' => $callbackUrl,
                ]
            );
        }

        return $this->server;
    }
    ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM