-
| 
         Hi, i changed all to the new api.  works for javascript clients. they are authentificated. final class Client implements LoggerAwareInterface
{
    use LoggerAwareTrait;
    private const MSG_WELCOME = 0;
    private const MSG_PREFIX = 1;
    private const MSG_CALL = 2;
    private const MSG_CALL_RESULT = 3;
    private const MSG_CALL_ERROR = 4;
    private const MSG_SUBSCRIBE = 5;
    private const MSG_UNSUBSCRIBE = 6;
    private const MSG_PUBLISH = 7;
    private const MSG_EVENT = 8;
    private WampRouter $router;
    private PawlClient $client;
    public function __construct(WampRouter $router, PawlClient $client)
    {
        $this->router = $router;
        $this->client = $client;
    }
    /**
     * Calls a RPC handler on the websocket server.
     *
     * @param array $payload
     * @param string $routeName
     * @param array $routeParameters
     */
    public function call(array $payload, string $routeName, array $routeParameters = []): void
    {
        $this->client->connect()
            ->then(
                function (WebSocket $connection) use ($payload, $routeName, $routeParameters) {
                    $this->logger->debug('Client connection resolved');
                    $route = $this->router->generate($routeName, $routeParameters);
                    $this->logger->debug('Calling RPC function on websocket server', ['route' => $route, 'payload' => $payload]);
                    try {
                        $message = json_encode(array_merge([self::MSG_CALL, uniqid('', true), $route], $payload), JSON_THROW_ON_ERROR);
                        $connection->send($message);
                    } catch (JsonException $exception) {
                        $this->logger->error('Could not encode message to call RPC function on websocket server.', ['exception' => $exception]);
                        throw $exception;
                    } finally {
                        $connection->close();
                    }
                },
                function (Throwable $throwable): void {
                    $this->logger->error('Client connection rejected', ['exception' => $throwable]);
                }
            );
    }
    /**
     * Publishes to a Topic on the websocket server.
     *
     * @param array $payload
     * @param string $routeName
     * @param array $routeParameters
     */
    public function publish(array $payload, string $routeName, array $routeParameters = []): void
    {
        $this->client->connect()
            ->then(
                function (WebSocket $connection) use ($payload, $routeName, $routeParameters) {
                    $this->logger->debug('Client connection resolved');
                    $route = $this->router->generate($routeName, $routeParameters);
                    $this->logger->debug('Publishing message to websocket server', ['route' => $route, 'payload' => $payload]);
                    try {
                        $message = json_encode([self::MSG_PUBLISH, $route, $payload, [], []], JSON_THROW_ON_ERROR);
                        $connection->send($message);
                    } catch (JsonException $exception) {
                        $this->logger->error('Could not encode message to publish to websocket server.', ['exception' => $exception]);
                        throw $exception;
                    } finally {
                        $connection->close();
                    }
                },
                function (Throwable $throwable): void {
                    $this->logger->error('Client connection rejected', ['exception' => $throwable]);
                }
            );
    }
}i used this service made everywhere i needed it an instance and -> publish()  | 
  
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
| 
         For server-to-server calls like these, you aren't going to be able to authenticate as a user within your app unless you pass some info along in the connect call from the  In the Symfony app for one of my clients, this is essentially what our  <?php declare(strict_types=1);
namespace App\Websocket\Client;
use Ratchet\Client;
use React\Promise\PromiseInterface;
/**
 * Thin wrapper around the `Ratchet\Client\connect()` function to allow for unit testing.
 */
class PawlClient
{
    private WebsocketUriBuilder $uriBuilder;
    private string $secret;
    public function __construct(WebsocketUriBuilder $uriBuilder, string $secret)
    {
        $this->uriBuilder = $uriBuilder;
        $this->secret     = $secret;
    }
    public function connect(): PromiseInterface
    {
        return Client\connect($this->uriBuilder->getServerUri(), ['wamp'], ['X-Secret-Header-With-Token' => hash('sha1', $this->secret)]);
    }
}Essentially we're sending a SHA1 hash of  <?php declare(strict_types=1);
namespace App\Websocket\Server;
use GuzzleHttp\Psr7\Message;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\RequestInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServerInterface;
class ServerToServerRequestValidator implements HttpServerInterface, LoggerAwareInterface
{
    use LoggerAwareTrait;
    private HttpServerInterface $app;
    private string $secret;
    public function __construct(HttpServerInterface $app, string $secret)
    {
        $this->app    = $app;
        $this->secret = $secret;
    }
    /**
     * @return mixed
     */
    public function onOpen(ConnectionInterface $conn, RequestInterface $request = null)
    {
        if (null === $request) {
            throw new \UnexpectedValueException('$request can not be null');
        }
        $conn->tokenAuth = false;
        $this->logger?->debug('Negotiating websocket request: ' . Message::toString($request));
        $response = null;
        // If the request has our token header, and the token does not pass validation, then issue a 403 and immediately reject the connection
        if ($request->hasHeader('X-Secret-Header-With-Token')) {
            if (!hash_equals(hash('sha1', $this->secret), $request->getHeaderLine('X-Secret-Header-With-Token'))) {
                $response = new Response(403, ['Content-Type' => 'text/plain; charset=utf8'], 'Access Denied', '1.1');
            } else {
                $conn->tokenAuth = true;
            }
        }
        // If there is no response, then we can proceed down the decorator stack
        if ($response === null) {
            return $this->app->onOpen($conn, $request);
        }
        // Send our response and close the connection
        $response = $response->withHeader('X-Powered-By', \Ratchet\VERSION);
        $this->logger?->debug('Sending websocket response: ' . Message::toString($response));
        $conn->send(Message::toString($response));
        return $conn->close();
    }
    /**
     * @param string $msg
     *
     * @return mixed
     */
    public function onMessage(ConnectionInterface $from, $msg)
    {
        return $this->app->onMessage($from, $msg);
    }
    /**
     * @return mixed
     */
    public function onClose(ConnectionInterface $conn)
    {
        return $this->app->onClose($conn);
    }
    /**
     * @return mixed
     */
    public function onError(ConnectionInterface $conn, \Exception $e)
    {
        return $this->app->onError($conn, $e);
    }
}If you need those server-to-server calls to authenticate as a specific user, you're going to need to tweak the API design a bit more to pass the user info along somehow (probably another request header, which I'd suggest would mean adding a   | 
  
Beta Was this translation helpful? Give feedback.
-
| 
         I used your suggestion but i resolved it on a bit different way. In My SecureTopicHandler <?php
class SecureTopicHandler
{
    public function secure(?ConnectionInterface $conn, Topic $topic, WampRequest $request, $payload = null, ?array $exclude = [], ?array $eligible = null, ?string $provider = null): void
    {
        /** @var $serverRequest \GuzzleHttp\Psr7\Request  */
        $serverRequest = $conn->__get('httpRequest');
        // check if user authorized
        $user = $this->clientManipulator->getUser($conn);
        if(!$user instanceof User){
            // if not check if its a server internal request.
            if($serverRequest->hasHeader('xxxxToken') && $this->container->hasParameter('websocket_secret')){
                $token = $serverRequest->getHeader('xxxxToken');
                if(!hash_equals(hash('sha1', $this->container->getParameter('websocket_secret')), $token[0])){
                    throw new FirewallRejectionException('Access denied');
                }
            }else{
                throw new FirewallRejectionException('Access denied');
            }
        }
    }
}works for now. guess this is fine.  | 
  
Beta Was this translation helpful? Give feedback.
I used your suggestion but i resolved it on a bit different way.
In My SecureTopicHandler