栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > PHP

深入浅出 Laravel Echo (3)

PHP 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

深入浅出 Laravel Echo (3)

看完 public channel 的流程,我们该来说说怎么跑通 private channel 了。

本文结合之前使用的 JWT 来做身份认证。

但这个流程,我们要先从前端说起。

socker.io

我们先写一个 demo:

window.Echo.private('App.User.3')
.listen('RssCreatedEvent', (e) => {
    that.names.push(e.name)
});

先创建 private channel:


privateChannel(name: string): SocketIoPrivateChannel {
    if (!this.channels['private-' + name]) {
 this.channels['private-' + name] = new SocketIoPrivateChannel(
     this.socket,
     'private-' + name,
     this.options
 );
    }

    return this.channels['private-' + name];
}

它与 public channel 的区别在于为 private channel 的 channel 名前头增加 private-。

接着我们需要为每次请求添加认证信息 headers:

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001',
    auth:
 {
     headers:
  {
      'authorization': 'Bearer ' + store.getters.token
  }
 }
});

这里,我们用 store.getters.token 存储着 jwt 登录后下发的认证 token。

好了,只要创新页面,就会先往 Laravel-echo-server 发送一个 subscribe 事件:


subscribe(): any {
    this.socket.emit('subscribe', {
 channel: this.name,
 auth: this.options.auth || {}
    });
}

我们来看看 Laravel-echo-server 怎么接收到这个事件,并把 auth,也就是 jwt token 发到后台的?在研究怎么发之前,我们还是先把 Laravel 的 private channel Event 建好。

RssCreatedEvent

我们创建 Laravel PrivateChannel:

// RssCreatedEvent
 'private_channel_'.Carbon::now()->toDateTimeString()];
    }
}

// routes/console.php
Artisan::command('echo', function () {
    event(new RssCreatedEvent());
})->describe('echo demo');

与 jwt 结合

修改 BroadcastServiceprovider 的认证路由为 api:

// 修改前
// Broadcast::routes();

// 修改后
Broadcast::routes(["middleware" => "auth:api"]);

当然,我们的认证方式也已经改成 JWT 方式了:

 [
 'guard' => 'api',
 'passwords' => 'users',
    ],

...

    'guards' => [
 'web' => [
     'driver' => 'session',
     'provider' => 'users',
 ],

 'api' => [
     'driver' => 'jwt',
     'provider' => 'users',
 ],
    ],

最后,别忘了把 BroadcastServiceprovider 加入 app.config 中。

注:更多有关 JWT 欢迎查看之前的文章

  1. 《学习 Lumen 用户认证 (一)》
  2. 学习 Lumen 用户认证 (二) —— 使用 jwt-auth 插件

Laravel-echo-server

有了前端和后台的各自 private channel,那必然需要用 Laravel-echo-server 来衔接。

先说回怎么接收前端发过来的 subscribe 事件和 token。

首先看 echo-server 初始化:

init(io: any): Promise {
    return new Promise((resolve, reject) => {
 this.channel = new Channel(io, this.options);
 this.redisSub = new RedisSubscriber(this.options);
 this.httpSub = new HttpSubscriber(this.server.express, this.options);
 this.httpApi = new HttpApi(io, this.channel, this.server.express, this.options.apiOriginAllow);
 this.httpApi.init();

 this.onConnect();
 this.listen().then(() => resolve(), err => Log.error(err));
    });
}

其中,this.onConnect():

onConnect(): void {
    this.server.io.on('connection', socket => {
 this.onSubscribe(socket);
 this.onUnsubscribe(socket);
 this.onDisconnecting(socket);
 this.onClientEvent(socket);
    });
}

主要注册了四个事件,第一个就是我们需要关注的:

onSubscribe(socket: any): void {
    socket.on('subscribe', data => {
 this.channel.join(socket, data);
    });
}

这就和前端呼应上了,接着看 join 函数:

join(socket, data): void {
    if (data.channel) {
 if (this.isPrivate(data.channel)) {
     this.joinPrivate(socket, data);
 } else {
     socket.join(data.channel);
     this.onJoin(socket, data.channel);
 }
    }
}

看 isPrivate() 函数:


protected _privateChannels: string[] = ['private-*', 'presence-*'];
    
    

isPrivate(channel: string): boolean {
    let isPrivate = false;

    this._privateChannels.forEach(privateChannel => {
 let regex = new RegExp(privateChannel.replace('*', '.*'));
 if (regex.test(channel)) isPrivate = true;
    });

    return isPrivate;
}

这也是印证了,为什么 private channel 要以 private- 开头了。接着看代码:


joinPrivate(socket: any, data: any): void {
    this.private.authenticate(socket, data).then(res => {
 socket.join(data.channel);

 if (this.isPresence(data.channel)) {
     var member = res.channel_data;
     try {
  member = JSON.parse(res.channel_data);
     } catch (e) { }

     this.presence.join(socket, data.channel, member);
 }

 this.onJoin(socket, data.channel);
    }, error => {
 if (this.options.devMode) {
     Log.error(error.reason);
 }

 this.io.sockets.to(socket.id)
     .emit('subscription_error', data.channel, error.status);
    });
}

就因为是 private channel,所以需要走认证流程:


authenticate(socket: any, data: any): Promise {
    let options = {
 url: this.authHost(socket) + this.options.authEndpoint,
 form: { channel_name: data.channel },
 headers: (data.auth && data.auth.headers) ? data.auth.headers : {},
 rejectUnauthorized: false
    };

    return this.serverRequest(socket, options);
}


protected serverRequest(socket: any, options: any): Promise {
    return new Promise((resolve, reject) => {
 options.headers = this.prepareHeaders(socket, options);
 let body;

 this.request.post(options, (error, response, body, next) => {
     if (error) {
  if (this.options.devMode) {
      Log.error(`[${new Date().toLocaleTimeString()}] - Error authenticating ${socket.id} for ${options.form.channel_name}`);
      Log.error(error);
  }

  reject({ reason: 'Error sending authentication request.', status: 0 });
     } else if (response.statusCode !== 200) {
  if (this.options.devMode) {
      Log.warning(`[${new Date().toLocaleTimeString()}] - ${socket.id} could not be authenticated to ${options.form.channel_name}`);
      Log.error(response.body);
  }

  reject({ reason: 'Client can not be authenticated, got HTTP status ' + response.statusCode, status: response.statusCode });
     } else {
  if (this.options.devMode) {
      Log.info(`[${new Date().toLocaleTimeString()}] - ${socket.id} authenticated for: ${options.form.channel_name}`);
  }

  try {
      body = JSON.parse(response.body);
  } catch (e) {
      body = response.body
  }

  resolve(body);
     }
 });
    });
}

到此,相信你就看的出来了,会把前端发过来的 auth.headers 加入发往后台的请求中。

测试

好了,我们测试下,先刷新页面,加入 private channel 中,

然后在后台,发一个事件出来,看前端是不是可以接收

总结

到此,基本就解释了怎么建立 private channel,然后利用 jwt 认证身份,最后将 Event 内容下发出去。

接下来我们就可以看看怎么建 chat room,然更多客户端加入进来聊天。

未完待续

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号