确保你的服务器已经安装了docker

云服务器部署/群晖部署

1.创建文件夹

云服务器

mkdir -p $(pwd)/bbk-qr/{conf,logs,static} && cd $(pwd)/bbk-qr
此时已cd进bbk-qr文件夹

群晖建议手动创建文件夹,每个人的路径不一样
手动新建3个文件夹
cd到docker文件夹

conf
logs
static

这是我的

cd /volume1/docker/Wskey转换/BBKWSkey扫码

2.启动容器

群晖手动替换$PWD自己挂载的路径
docker run -dit \
  -v $PWD/conf:/data/conf \
  -v $PWD/logs:/data/logs \
  -p 2081:81 \
  --restart=always \
  --name bbk-qr \
  neuynp8oido4ejj/qr:latest


如果页面上想显示wskey出来
可以用下面的命令
同时conf.json文件内的 "loginReturnCK": true 需要设置 true

然后把下面的index.html下载下来,替换成显示wskey的网页,也可以复制下面显示wskey的index.html替换里面的代码
目录static/index.html

群晖手动替换$PWD自己挂载的路径
docker run -dit \
  -v $PWD/conf:/data/conf \
  -v $PWD/logs:/data/logs \
  -v $PWD/static:/data/static \
  -p 2081:81 \
  --restart=always \
  --name bbk-qr \
  neuynp8oido4ejj/qr:latest

3.修改conf.json文件内容(每次修改conf.json需要重启容器)

$(pwd)/conf 目录下的conf.json文件 填写token等信息

4. 重启容器

docker restart bbk-qr

5. 浏览器访问:http://你的IP:2081

云服务器记得放行端口

二维码只能用后置摄像头扫码,微信内部识别不到

显示wskey的index.html文件

可以用这个替换容器内的 static/index.html 文件:点击下载

也可以手动替换static/index.html内容

显示wskey的index.html

<!DOCTYPE html>
<html lang="zh-cn">

<head>
    <meta charset="utf-8">
    <meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-touch-fullscreen" content="yes" />
    <meta name="format-detection" content="telephone=no,address=no" />
    <meta name="apple-mobile-web-app-status-bar-style" content="white" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />

    <title>qr</title>
    <style>
        body,
        html {
            margin: 0;
            padding: 0;
        }
        .container {
            display: flex;
            flex-direction: column;
            justify-content: space-around;
            height: calc(100vh - 430px);
        }

        .qr {
            display: flex;
            justify-content: center;
            align-items: center;
            text-align: center;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            inset: 0px;
            height: 100%;
            /* background-color: rgba(0, 0, 0, 0.45); */
            z-index: 1001;
        }

        .qrcontainer {
            position: relative;
            width: 256px;
            padding: 16px;
            border-radius: 8px;
            border: 1px solid rgb(109, 138, 136);
            background-color: rgb(255, 255, 255);
            box-shadow: rgb(0 0 0 / 20%) 0px 0px 7px 3px;
            box-sizing: content-box;
        }

        #tip {
            display: none;
            justify-content: center;
            align-items: center;
            position: absolute;
            top: 47px;
            left: 16px;
            width: 256px;
            height: 256px;
            color: rgb(255, 255, 255);
            background-color: rgba(0, 0, 0, 0.5);
        }

        .desTitle {
            word-break: break-word;
            padding-bottom: 10px;
        }

        .des {
            word-break: break-word;
            padding-top: 10px;
        }
    </style>
</head>

<body>
<div class="container">
</div>
<div id="qr" class="qr">
    <div class="qrcontainer">
        <div class="desTitle">
            <span id="tipt">loading...</span>|<a href="javascript:void(0)" id="refresh123" >手动刷新</a>
        </div>
        <div id="qrbox">
            <img alt="" id="qrCode"/>
        </div>
        <div id="tip">
            <h3>二维码已失效,请刷新</h3>
        </div>
        <div id="des" class="des"></div><!--tip-->
    </div>
</div>
</body>
<script type="text/javascript">
  document.getElementById("des").style.display = 'none';
  document.getElementById('refresh123').addEventListener('click', function () {
    let timeStamp = new Date().getTime();
    ajax({
      url: '/d/getQR?force=1&t=' + timeStamp,
      method: 'get',
      success: function (data) {
        if (data.code !== 200) {
          if (data.errMsg) {
            showTips(data.errMsg);
          } else {
            showTips("获取二维码出错了,请刷新页面");
          }
        } else {
          if (data.data.qr && data.data.timeout) {
            i = parseInt(data.data.timeout);
            location.reload();
          }
        }
      },
    });
  });
  get_code();
  let a={}, i=180;
  function qrExpire() {
    document.getElementById("tip").style.display = 'flex';
    window.clearInterval(a.ib)
  }
  function showTips(tip) {
    document.getElementById("des").style.display = 'flex';
    document.getElementById("des").innerHTML = tip;
  }
  function get_code() {
    let timeStamp = new Date().getTime();
    ajax({
      url: '/d/getQR?t=' + timeStamp,
      method: 'get',
      success: function (data) {
        if (data.code !== 200) {
          if (data.errorMsg) {
            showTips(data.errorMsg);
          } else {
            showTips("获取二维码出错了,请手动刷新页面");
          }
          // location.reload();
        } else {
          if (data.data.qr && data.data.timeout) {
            i = parseInt(data.data.timeout);
            document.getElementById("qrCode").setAttribute("src",data.data.qr);
            document.getElementById("tipt").innerHTML = `有效期剩余${--i}秒`;
            a.ib = setInterval(() => {
              if (i <= 0) {
                qrExpire();
                // location.reload();
              } else {
                document.getElementById("tipt").innerHTML = `有效期剩余${--i}秒`;
              }
            }, 1000);
            checkLogin();
          }
        }
      },
    });
  }
  function checkLogin() {
      let timeStamp = new Date().getTime();
      ajax({
        url: '/d/status?t=' + timeStamp,
        method: 'get',
        success: function (data) {
          console.log(JSON.stringify(data));
          if (data.code == 500 || data.code == 202) {
              qrExpire();
              showTips(data.errorMsg);
          } else if (data.code == 408) {
            qrExpire()
            // location.reload();
          } else if (data.code == 410 && data.data) {
            window.clearInterval(a.ib)
            showTips(data.data.wskey);
            qrExpire();
          } else {
              setTimeout(checkLogin, 1000)
          }
        }
      });
  }
  function ajax(options) {
    var url = options.url;
    var method = options.method;
    var data = options.data;
    var success = options.success;
    var ajax = new XMLHttpRequest();
    ajax.open(method, url);
    if (method == 'post') {
      ajax.setRequestHeader('Content-type', 'application/json');
    }
    ajax.send(JSON.stringify(data));
    ajax.onreadystatechange = function () {
      if (ajax.readyState == 4 && ajax.status == 200) {
        success(JSON.parse(ajax.responseText));
      }
    };
  }
</script>
</html>

如下是conf.json文件参数介绍:

{
 "server": {
  // 机器人获取的token(必填参数)
  "token": "",

  // 扫码成功后页面检测状态接口是否返回wskey true:返回 false不返回(可选参数)
  // 页面替换了显示wskey后此栏需设置true
  "loginReturnCK": false,

  // wskey安全考虑 推荐配置该加密秘钥,可手动设置(必须8-32位字符),如果enableEncrypt参数为true启用了wskey加密 此参数没设置时会随机生成一个,此秘钥需妥善保存 不能泄露!!!(可选参数)
  // 页面替换了显示wskey后此栏不需要设置
  "encryptKey": "",

  // 推荐配置true。true:启用wskey安全加密 false:不启用wskey安全加密 (可选参数)
  // 页面替换了显示wskey后此栏需设置false
  "enableEncrypt": false
  // 获取wskey之后是否将其转换app_open(JD_COOKIE)上传至青龙 true:上传 false:不上传
  "convertWskey": true
 },

 // 青龙相关配置(可选参数对象 可全部不填 如果填了 则以下参数都需要填写)
 "qinglong": {
  // 青龙面板ip(必须填写)
  "ip": "",
  //青龙面板端口(必须填写)
  "port": 0,
  // 青龙面板clientId (必须填写)
  "clientId": "",
  // 青龙面板clientSecret (必须填写)
  "clientSecret": "",
 },
 // 扫码成功通知配置(可选参数对象)
 "notify": {
  "tgBot": {
   // telegram机器人token (可选参数)
   "botToken": "",
   // 接收消息的用户ID (可选参数)
   "userId": "",
   // http代理,留空则不使用 格式:http://127.0.0.1:1080 (可选参数)
   "proxyUrl": ""
  },

  // 扫码成功后 主动以POST方式推送wskey到以下url接口 接收的参数格式:{"pin":"xx","wskey":"xx"},留空则不推送(可选参数对象)
  "custom": {
   // 推送wskey地址 格式: http://ip/xxx (可选参数)
   "url": "",
   "headers": {
    // 推送的同时携带的请求头 比如认证信息 以下auth是例子可删(可选参数)
    "auth": "123123123"
   }
  }
 }
}
最后修改:2023 年 01 月 26 日
如果觉得我的文章对你有用,别忘了点赞或赞赏,让我知道路上有你陪伴。