2017-04-26 32 views
0

我正在为我的Symfony 3应用程序编写卫兵来处理OAuth。如何从早期/自动加载Symfony 3路由器生成绝对URL

作为它的一部分,在我的一个服务中,我需要生成一个绝对URL来发送到Twitter作为回叫URL。

#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' 

该记录器是临时调试。

#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); 
    ... 
} 

而且,当输出$callbackUrl的日志,它只是说,本地主机,即使我使用的是不同的网址来访问它。

http://localhost/connect/twitter/check 

但是,如果我从我的控制器执行相同的操作,它会输出完整正确的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); 
     ... 

此输出:

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

dev.myapi.com域是建立在我的hosts文件,并点到本地主机,使其更容易到我的本地应用程序之间的区别,也使其更容易整合与OAuth服务。

回答

0

我设法通过设置路由器上下文来解决这个问题。 我已经加载了RequestStack来访问用户的IP,所以我用它来设置路由的上下文,然后路由器按预期工作。 我碰到试图在构造函数中使用RequestStack的problems,所以我最终重构了它,以便尽可能晚地使用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; 
    } 
    ... 
}