| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- <?php
- /**
- * Websocket 后台封装类,用于实现token 和 uid 的绑定关系
- * 前端连接 websocket 时,可以使用带上 token,workerman根据 token 查询出 uid,以实现 client_id 和 uid 的绑定关系
- */
- namespace app\common\logic;
- use \GatewayClient\Gateway;
- use think\Cache;
- use think\Config;
- class Websocket
- {
- const TOKEN_LIMIT = 10; // 同一用户 token 上限
- private $auth_duration; // 登录token 有效期
- private $_redis = null;
- public function __construct()
- {
- $this->auth_duration = Config::get('session')['expire']; //设置成和session相同的过期时间
- $this->_redis = Cache::init()->handler(); // redis 句柄
- }
- /**
- * 登录完成后,调用该方法,在 websocket 服务端注册一个有效token,并产生 token 和 uid 的对应关系记录
- * @param $token
- * @param $adminId
- * @return void
- */
- public function registerToken($token, $adminId)
- {
- // uid 对应的 token列表, 同一个账号,可能存在多个人同时登录的情况,在目前的业务场景下,并未禁止
- // 所以要能够实现多个登录终端的对应
- $tokenCacheKey = "ayam:push:uid:{$adminId}:token";
- $tokenList = $this->_redis->get($tokenCacheKey);
- $tokenList = json_decode($tokenList, true);
- empty($tokenList) && $tokenList = array();
- $tokenList[$token] = time() + $this->auth_duration;
- // 限制 token 的个数,超出预设值,剔除最先登录的
- if (count($tokenList) > self::TOKEN_LIMIT) { // 限制 TOKEN 数
- $tokenList = array_slice($tokenList, -self::TOKEN_LIMIT);
- }
- $this->_redis->setex($tokenCacheKey, $this->auth_duration, json_encode($tokenList));
- // token 对应的 uid,这样 workerman 那边可以通过 token 查询对应的 uid
- $cacheKey = "ayam:push:token:{$token}:uid";
- $this->_redis->setex($cacheKey, $this->auth_duration, $adminId);
- }
- /**
- * 重置登录token有效
- *
- * @param $token string 查询的token
- * @param $adminId string 所属用户id
- *
- * @return void
- */
- public function resettingToken($token, $adminId)
- {
- // uid 对应的 token列表, 同一个账号,可能存在多个人同时登录的情况,在目前的业务场景下,并未禁止
- // 所以要能够实现多个登录终端的对应
- $tokenCacheKey = "ayam:push:uid:{$adminId}:token";
- $cacheKey = "ayam:push:token:{$token}:uid";
- if (!$this->_redis->exists($cacheKey)) {
- $tokenList = $this->_redis->get($tokenCacheKey);
- $tokenList = json_decode($tokenList, true);
- empty($tokenList) && $tokenList = array();
- $tokenList[$token] = time() + $this->auth_duration;
- // 限制 token 的个数,超出预设值,剔除最先登录的
- if (count($tokenList) > self::TOKEN_LIMIT) { // 限制 TOKEN 数
- $tokenList = array_slice($tokenList, -self::TOKEN_LIMIT);
- }
- $this->_redis->setex($tokenCacheKey, $this->auth_duration, json_encode($tokenList));
- // token 对应的 uid,这样 workerman 那边可以通过 token 查询对应的 uid
- $this->_redis->setex($cacheKey, $this->auth_duration, $adminId);
- }
- }
- /**
- * 注销连接 token
- * @param $token
- * @param $adminId
- * @return void
- */
- public function destroyToken($token, $adminId)
- {
- $uidCacheKey = "ayam:push:token:{$token}:uid";
- $this->_redis->del($uidCacheKey);
- $tokenCacheKey = "ayam:push:uid:{$adminId}:token";
- $tokenList = $this->_redis->get($tokenCacheKey);
- if (empty($tokenList)) {
- $tokenList = array();
- } else {
- $tokenList = json_decode($tokenList, true);
- }
- if (isset($tokenList[$token])) { // 只清除指定的 token
- unset($tokenList[$token]);
- }
- // 若该uid还存在token,做更新,否则删除key,减少占用
- if (count($tokenList) > 0) {
- $this->_redis->set($tokenCacheKey, json_encode($tokenList));
- } else {
- $this->_redis->del($tokenCacheKey);
- }
- }
- /**
- * 发送消息给指定的用户
- * @param $uid int
- * @param $data string
- * @return void
- */
- public function sayToUid($uid, $data)
- {
- if (!is_string($data) || empty($data)) {
- exception('data 参数需为字符串类型');
- }
- empty($uid) && exception('请传入 uid参数');
- Gateway::$registerAddress = config('WEBSOCKET_REGISTER_ADDR');
- // 数据格式示例:{"error_code":0,"data":{"action":"authSuccess","data":{"code":0,"message":""}}}
- Gateway::sendToUid($uid, $data);
- }
- }
|