swoft-cloud / swoft

🚀 PHP Microservice Full Coroutine Framework
https://swoft.org
Apache License 2.0
5.58k stars 788 forks source link

Swoft 2.0 - Auth and Sharing between Http and Wss Server #857

Closed goddanao closed 5 years ago

goddanao commented 5 years ago

QUESTION

Q A
Bug report? no
Feature request? no
Swoft version 2.0.4-beta
Swoole version 4.4.2-alpha
PHP version 7.2.9
Runtime environment Docker

First of all i'm a newby with swoft, please be patient.. I'm struggling trying to understand how can i implement a simple auth. Looking for swoft/auth helps, but it's for swoft 1.0 and i still missing how can i share user data between http and wss and how to protect routes/services.

Can you point me in the right direction?

Thankyou very much, your work is awesome.

stelin commented 5 years ago

You can use middleware to achieve auth

goddanao commented 5 years ago

I have played with swoft/auth dev:master (which is currently migrating to swoft 2.0) and with its AuthMiddleware, implementing my custom AuthManagerInterface and AccountTypeInterface. JWT Token are generated, stored client side, trasmitted and autheticated on each(?) Http request / Ws Message.

I got few general questions:

While working with the websocket server i tried to implement a websocket extension for "permessage-deflate" compression support. In the WsModule@OnHandshake i can determine if the extension is needed

/**
     * @OnHandshake()
     * @param Request $request
     * @param Response $response
     * @return array [bool, $response]
     */
    public function checkHandshake(Request $request, Response $response): array
    {
        if(config('websocket.deflate')) {
            if($extensions = $request->getHeaderLine("Sec-WebSocket-Extensions")) {
                $extensions = array_flip(array_map('trim', explode(";", $extensions)));
                if(isset($extensions['permessage-deflate']))
                    $response = $response->withAddedHeader("Sec-WebSocket-Extensions", "permessage-deflate");
            }
        }
        return [true, $response];
    }

What i need is to switch the Parser in WsMessageContext with the DeflateParser when needed.

class DeflateParser extends JsonParser implements MessageParserInterface
{
    public function encode(Message $message): string
    {
        $ctx = deflate_init(ZLIB_ENCODING_RAW);
        return deflate_add($ctx, parent::encode($message), ZLIB_FINISH);
    }

    public function decode(string $data): Message
    {
        $ctx = inflate_init(ZLIB_ENCODING_RAW);
        return parent::decode(inflate_add($ctx, $data, ZLIB_FINISH));
    }
}

I'm currently implementing my custom @OnMesage handler because the default one don't send the Ext Data part of the message to the Controllers (i can't find a way to get it on the controller, but decoding again the frame->data). I think is also the right place to do the Parser swap based on handshake.

I know that the deflate support must not be bound to the Parser, but it's a best effort solution for what i'm trying to obtain. If there's a better way of doing this with swoft, a WebSocket extensions support that i'm not aware of or cleaner way, let me know.

inhere commented 5 years ago

hi @goddanao

We will release 2.0.5 soon.

The ws server's message processing method can get objects such as Message, Request, Response, and now can get all the information, including the ext part.

eg:

use Swoft\WebSocket\Server\Message\Message;
use Swoft\WebSocket\Server\Message\Request;

// ...

    /**
     * Message command is: 'test.req'
     *
     * @param Request $req
     *
     * @return void
     * @MessageMapping("req")
     */
    public function injectRequest(Request $req): void
    {
        $fd = $req->getFd();

        Session::mustGet()->push("(your FD: $fd)message data: " . \json_encode($req->getMessage()->toArray()));
    }

    /**
     * Message command is: 'test.msg'
     *
     * @param Message $msg
     *
     * @return void
     * @MessageMapping("msg")
     */
    public function injectMessage(Message $msg): void
    {
        // $data = $msg->getData();
        // $ext = $msg->getExt();
        Session::mustGet()->push('message data: ' . \json_encode($msg->toArray()));
    }

Can also:

// $msg is Swoft\WebSocket\Server\Message\Message
$msg = context()->getMessage();
$cmd = $msg->getCmd();
$data = $msg->getData();
$ext = $msg->getExt();
inhere commented 5 years ago

Other

inhere commented 5 years ago

hi @goddanao

The v2.0.5 has been released. please try it. Hope that has solved your problem.