Codigo para validacao de requisicoes REST multi-store

De Tek-System Wiki
Revisão de 19h12min de 21 de fevereiro de 2018 por Rafael Padovani (discussão | contribs)
Ir para navegação Ir para pesquisar

O codigo a seguir é o mais atualizado até o momento. Note que a validacao possuiAcessoANovosPedidos() é falha e vai precisar ser refeita. O ideal é encontrar um padrão para as seguintes requisições:

   Path_Categorias           = 'categories';
   Path_CategoriasMove       = 'categories/%d/move';  
   Path_Produtos             = 'products';       
   Path_Atributos            = 'products/attributes';
   Pesquisa_Atributos        = '?searchCriteria[filterGroups][0][filters][0][field]=is_filterable_in_search&searchCriteria[filterGroups][0][filters][0][value]=1&searchCriteria[filterGroups][0][filters][0][conditionType]=eq&' +
                             'searchCriteria[filterGroups][1][filters][1][field]=attribute_code&searchCriteria[filterGroups][1][filters][1][value]=cor,variacao,acabamento,tamanho,grade,tecido&searchCriteria[filterGroups][1][filters][1][conditionType]=nin';
   
   Path_OpcoesAtributos      = 'products/attributes/%s/options';
   Path_AtributoConfiguracao = 'products/attribute-sets/sets/list?searchCriteria';
   Path_ProdutoConfiguravel  = 'configurable-products/%s/child';
   Path_EstoqueProduto       = 'products/%s/stockItems/1';
   Path_ProdutosMedia        = 'products/%s/media';
   Path_DeletaProdutosMedia  = 'products/%s/media/%s';
   Path_AprovacaoPgtoPedido  = 'order/%s/invoice';  
   Path_PedidosNovos         = 'orders?&searchCriteria[filterGroups][1][filters][1][field]=status&searchCriteria[filterGroups][1][filters][1][value]='+Integracao_CodStatusMagentoDocPagtoAprovado+'&searchCriteria[filterGroups][1][filters][1][conditionType]=eq&' +
                             'searchCriteria[filterGroups][2][filters][2][field]=store_id&searchCriteria[filterGroups][2][filters][2][value]=%s&searchCriteria[filterGroups][2][filters][2][conditionType]=in';
   Path_DadosPostagemPedido  = 'order/%s/ship';
   Path_Comentarios          = 'orders/%s/comments';
   
   
   'orders?&searchCriteria[filterGroups][1][filters][1][conditionType]=eq&' +
                             'searchCriteria[filterGroups][2][filters][2][field]=store_id&searchCriteria[filterGroups][2][filters][2][value]=%s&searchCriteria[filterGroups][2][filters][2][conditionType]=in';


O grande desafio é criar um padrão para as requisições acima. Note também que eh muito provável que novas requisições sejam necessários para liberação no futuro. O código deve ser robusto e extremamente otimizado, já que toda requisição de url vai passar pela validação.

Código:

   /**
    * Copyright © 2013-2017 Magento, Inc. All rights reserved.
    * See COPYING.txt for license details.
    */
   
   namespace Magento\Webapi\Controller\Rest;
   
   use Magento\Framework\Webapi\Rest\Request as RestRequest;
   use Magento\Webapi\Controller\Rest\Router;
   use Magento\Store\Model\StoreManagerInterface;
   use Magento\Store\Model\Store;
   use Magento\Framework\Webapi\Authorization;
   use Magento\Framework\Exception\AuthorizationException;
   use PhpParser\Node\Expr\Array_;
   
   
   /**
    * This class is responsible for validating the request
    */
   class RequestValidator
   {
       /**
        * @var RestRequest
        */
       private $request;
   
       /**
        * @var Router
        */
       private $router;
   
       /**
        * @var StoreManagerInterface
        */
       private $storeManager;
   
       /**
        * @var Authorization
        */
       private $authorization;
   
       /**
        * Initialize dependencies
        *
        * @param RestRequest $request
        * @param Router $router
        * @param StoreManagerInterface $storeManager
        * @param Authorization $authorization
        */
       public function __construct(
           RestRequest $request,
           Router $router,
           StoreManagerInterface $storeManager,
           Authorization $authorization
       ) {
           $this->request = $request;
           $this->router = $router;
           $this->storeManager = $storeManager;
           $this->authorization = $authorization;
       }
   
       /**
        * Validate request
        *
        * @throws AuthorizationException
        * @throws \Magento\Framework\Webapi\Exception
        * @return void
        */
       public function validate()
       {
           $this->checkPermissions();
           $route = $this->router->match($this->request);
           if ($route->isSecure() && !$this->request->isSecure()) {
               throw new \Magento\Framework\Webapi\Exception(__('Operation allowed only in HTTPS'));
           }
       }
   
       /**
        * Perform authentication and authorization.
        *
        * @throws \Magento\Framework\Exception\AuthorizationException
        * @return void
        */
       private function checkPermissions()
       {
           $route = $this->router->match($this->request);
   
           if (!$this->authorization->isAllowed($route->getAclResources())) { // SE NAO ESTA AUTORIZADO
   
               $params = ['resources' => implode(', ', $route->getAclResources())];
               throw new AuthorizationException(
                   __(AuthorizationException::NOT_AUTHORIZED, $params)
               );
   
           }else { // SE ESTA AUTORIZADO
               $naoAutorizado = ["Não autorizado" => "Voce nao possui autorizacao"];
   
               $requisicaoCompleta = $this->request->getUriString();
               $strRequisicaoCompleta = (string)$requisicaoCompleta;
               $userName = $this->request->get("username");
   
               if($this->possuiAcessoParaGerarToken($requisicaoCompleta)){
                   $lojaDeAcessoPermitido = $this->verificaLojaDeAcessoDoCliente($userName);
                   $this->gravaUserNameNaSessao($userName,$lojaDeAcessoPermitido );
                   return;
               }
   
               if($this->possuiAcessoANovosPedidos($requisicaoCompleta,3)){return; }
   
               throw new AuthorizationException(
                   __(AuthorizationException::NOT_AUTHORIZED, $naoAutorizado)
               );
   
           }
   
       }
    
       private function possuiAcessoParaGerarToken($url){
           return ( ( strpos($url, '/rest/V1/integration/admin/token') !== false ) );
       }
   
       private function possuiAcessoANovosPedidos($url,$lojaQueEstaTentandoAcessar){
           //NOTA: Essa url tem que ser completamente reestruturada.
           return ( ( strpos($url, 'orders') !== false ) && ( strpos($url, 'store_id') !== false ) && ($_SESSION["lojaAcessoPermitido"] == $lojaQueEstaTentandoAcessar) );
       }
   
       private function verificaLojaDeAcessoDoCliente($userName){ // CRIAMOS UM NOVO CAMPO NA TABELA ADMIN_USER, ESTE SE CHAMA STORE_ID_SOLUCAO PARA INFORMAR QUAL LOJA ESTE USUARIO TEM ACESSO.
   
           $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
           $resource = $objectManager->get('Magento\Framework\App\ResourceConnection');
           $connection = $resource->getConnection();
           $tableName = $resource->getTableName('admin_user');
   
           $sql = $connection->select()
               ->from($tableName)
               ->where('admin_user.username = ?', $userName);
   
           $result = $connection->fetchRow($sql);
           $arr = $result["store_id_solucao"];
   
           //retorna a loja que o usuario tem acesso
           return $arr;
       }
   
       private function gravaUserNameNaSessao($userName, $lojaComAcessoPermitido){
           //grava username na sessao, pois so temos acesso a ela na geracao do token
           //talvez seja interessante encriptar estes dois dados futuramente
           $_SESSION["usuario"]= $userName;
           $_SESSION["lojaAcessoPermitido"] = $lojaComAcessoPermitido;
       }
   
   }