最新消息

欢迎来到 DH Hub!

我们是 南信大 DH 互联网技术社团

在这里收集当下火热的技术文章,并且分到对应板块内,作为社团的技术积累,供历届社友学习

本站不开放注册,访客可以正常浏览

  • 由于一些解析原因,建议先在本地编辑器写完以后再上传
  • 由于服务器原因,在编辑主题 / 回复时会有一定卡顿,请谅解。

二维码远程签到机

主题 作者
成员
09
10
2
文章类型
完全原创 —— 自由转载
本文仅为技术讨论,不鼓励翘课行为
部分老师有设置5秒二维码签到的坏毛病,不能惯着他们
那么,我们的需求是:
  • 发送者在前端扫描二维码
  • 后端接收发送者获取的二维码数据,低延迟同步给接收者
  • 接收者扫描前端生成的二维码
虽然用长轮询也能实现以上需求,但Websocket是更加优雅、便捷的选择
本文将使用原生JS编写前端(没必要用框架),Golang编写后端(减少心智负担)

首先来解决后端
虽然这只是个小工具,但毕竟部署在公网,裸跑大概率会被脚本小子撅
所以随便签个证书吧,静态资源用BasicAuth意思一下,可以加个错误等待时间什么,自行发挥
C-like:
//go:embed html
var html embed.FS
var hfs http.Handler

func init() {
    fsys, err := fs.Sub(html, "html")
    if err != nil {
        panic(err)
    }
    hfs = http.FileServer(http.FS(fsys))
}

func handleHtml(w http.ResponseWriter, r *http.Request) {
    name, passwd, ok := r.BasicAuth()
    if !ok {
        w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
        w.WriteHeader(http.StatusUnauthorized)
        return
    }
    if name != "fkqrcode" || passwd != "nopasswd" {
        http.Error(w, "Fuck off!", http.StatusUnauthorized)
        return
    }
    hfs.ServeHTTP(w, r)
}
Websocket部分抄样例即可,用一个channel保存二维码
C-like:
var qrch = make(chan string, 3)
var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

func handleSend(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        return
    }
    defer conn.Close()

    for {
        _, data, err := conn.ReadMessage()
        if err != nil {
            log.Printf("failed to read data from %s : %v\n", r.RemoteAddr, err)
            return
        }
        qr := string(data)
        log.Println(qr)
        select {
        case qrch <- qr:
        default:
        }
    }
}

func handleReceive(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        return
    }
    defer conn.Close()

    for {
        qr := <-qrch
        err = conn.WriteMessage(websocket.TextMessage, []byte(qr))
        if err != nil {
            log.Printf("failed to send qr to %s : %v\n", r.RemoteAddr, err)
            return
        }
    }
}
前端使用adapter instascan qrcode三个库
HTML:
<video id="preview"></video>
<select id="select">
</select>
<button onclick="startScan()" id="start" disabled>Start</button>

<script>
    let ws = new WebSocket("wss://" + location.host + "/send");
    let err = () => location.reload();
    ws.onclose = err;
    ws.onerror = err;

    let opts = {};
    let scanner = new Instascan.Scanner({ video: document.getElementById('preview') });
    scanner.refractoryPeriod = 1000;
    scanner.mirror = false;
    scanner.addListener('scan', (content) => ws.send(content));
    Instascan.Camera.getCameras()
        .then((cameras) => {
            if (cameras.length > 0) {
                let select = document.getElementById('select');
                for (camera of cameras) {
                    opts[camera.name] = camera;
                    select.appendChild(new Option(camera.name));
                }
                document.getElementById('start').disabled = '';
            } else {
                err();
            }
        })
        .catch(err);

    function startScan() {
        scanner.stop()
            .then(() => {
                let select = document.getElementById('select');
                scanner.start(opts[select.item(select.selectedIndex).text]).catch(err)
            })
            .catch(err);
    }
</script>

HTML:
<div id="qrcode"></div>
<script>
    let qrcode = new QRCode(document.getElementById("qrcode"), "https://" + location.host);
    let ws = new WebSocket("wss://" + location.host + "/receive");
    ws.onmessage = () => {
        qrcode.clear();
        qrcode.makeCode(event.data);
    };
    ws.onclose = location.reload();
    ws.onerror = location.reload();
</script>

ok齐活
 
最后编辑:
成员
荣誉成员
09
5
2
学习通二维码签到实际上不会过期,老师设置5秒都没问题,时间验证只在学习通 app 前端。解码二维码可以得到一个 code,只需要那个 code 就可以完成签到。

二维码签到已经是学习通最严格的验证了,密码、手势签到的验证完全在前端,连发都不用发。

相关代码可见于 https://github.com/Clansty/superstar-checkin ,目前与 QQ 相关的功能(如群聊发送二维码)处于失效状态,但其它功能可用,可供参考。笔者曾遇到老师设置完手势还没发出来就签上到的情况,非常尴尬,还请注意延时,避免这种情况。
 
主题 作者
成员
09
10
2
学习通二维码签到实际上不会过期,老师设置5秒都没问题,时间验证只在学习通 app 前端。解码二维码可以得到一个 code,只需要那个 code 就可以完成签到。

二维码签到已经是学习通最严格的验证了,密码、手势签到的验证完全在前端,连发都不用发。

相关代码可见于 https://github.com/Clansty/superstar-checkin ,目前与 QQ 相关的功能(如群聊发送二维码)处于失效状态,但其它功能可用,可供参考。笔者曾遇到老师设置完手势还没发出来就签上到的情况,非常尴尬,还请注意延时,避免这种情况。
学习通更新了机制,现在code和enc都会改变
 
主题 作者
成员
09
10
2
在服务端模拟签到可以做到全自动(对接受者来说),但是不确定学习通app是否有其他检测方式。最稳妥的办法还是让同学多带一部手机:biggrin:,本帖的小工具仅仅是换了个思路
 
顶部