基于 Go + 小程序实现网页端“扫码登录”实战

不想使用账号和密码登录,害怕被攻击,也不想做注册等功能;不想使用手机号和验证码登录,没有钱也没有资质去做这些。我想到了二维码,通过二维码进行登录。这里有一个核心的问题还是如何鉴权? 在了解小程序后,我就决定使用小程序扫描二维码登录,使用小程序自带的微信账户体系完成鉴权。 我们要知道,二维码(QR Code)是连接物理世界与数字世界的“虫洞”。在登录系统中,它承载着一个临时的身份信标。 在实现这个Web登录功能的过程中,我们需要: 1. 生成有效二维码 这个二维码需要显示在网页上,供用户扫码登录,登录二维码通常包含一个加密的 URL 或一个唯一的 UUID(通用唯一识别码)。 这个唯一识别码需要具备的特性: 唯一性: 每一对扫描动作都必须对应一个独一无二的 ID。 时效性: 二维码必须配合 Redis 设置过期时间(如 2 分钟),逾期自动失效。 在本项目中,我们将用户的微信 OpenID 作为 Key,生成的验证码作为 Value,使用Redis进行存储: // 存储验证码,并设置 5 分钟过期 err := rdb.Set(ctx, "user:123:code", "8888", 5*time.Minute).Err() // 读取验证码 val, err := rdb.Get(ctx, "user:123:code").Result() 当有了二维码内容后,我们需要工具来生成二维码,在 Go 生态中,我们使用 skip2/go-qrcode 库来完成像素的绘制: // 生成二维码字节数组 var png []byte png, _ = qrcode.Encode("91demo.top"+sessionID, qrcode.Medium, 256) 为了防止用户伪造扫码请求,二维码里的内容通常是加密的或者是不可预测的长随机数(UUID)。只有真实存在的 ID 才能通过后端的 Redis 校验。 2. 传输二维码 当在服务端生成二维码后,还需要传递给浏览器,让浏览器进行显示,用户才可以扫码。这里有两个方法:1,生成图片文件,然后浏览器下载后显示。2,将图片内容转为Base64字符串传递给浏览器。这里我们选择了后者,我们不希望在用户硬盘上产生大量的临时 .png 文件。 在Go中可以这样操作: // 转换为前端可直接识别的 Data URL base64Img := "data:image/png;base64," + base64.StdEncoding.EncodeToString(png) 为了让前端不至于崩溃,后端必须返回统一的格式。 func HandleLogin(c *gin.Context) { // 逻辑处理... c.JSON(200, gin.H{ "code": 1, "content": base64Img, }) } 在前端,我们不再需要引入沉重的第三方库来做简单的请求。浏览器原生提供的 Fetch API 简洁且基于 Promise。 ...

2025-03-15 · 2 min · Eagle

实战笔记:为了不再发错下载链接,我给工具箱加了“扫码鉴定”

小工具可以解决大问题。在软件发布流程中,最尴尬的事情莫过于:宣传图已经发出去了,用户扫码后却发现链接打不开,或者下载了一个旧版本的安装包。 我就亲身经历过这么一次“翻车”事故。 事故现场:一个 URL 引起的麻烦 有一次,我在更新软件下载页面后,由于换了一个新的 URL 地址,在生成二维码阶段没有进行严格校验,就直接把二维码发布了出去。 结果当用户兴冲冲地扫码下载时,发现软件运行异常。我对比了半天才发现,生成二维码时填写的 URL 链接版本号写错了一个字符,导致用户下载到了一个有问题的版本,这是偶然中的极端。 虽然这只是一个低级错误,但它让我意识到:在二维码挂载后、正式发布前,必须有一个极简的“内容鉴定”环节。 痛点:如何快速、无痛地校验? 通常我们校验二维码,习惯性地直接拿手机扫一下。但如果二维码指向的是一个大容量的 APP 下载包或复杂的跳转链接,扫码后手机会自动触发下载或进入复杂的网页路径。 我其实并不想真的下载并安装测试(那是后续的 QA 环节),我只是想一眼看到二维码里到底写了什么字符,确定那个 URL 是不是我想要的那一个。 实现:借力小程序的原生能力 既然发现了痛点,解决起来就非常顺手了。得益于微信生态对扫码的深度支持,我在“豆子工具”里实现了一个“二维码识别”功能: 核心逻辑:直接调用小程序的 wx.scanCode 接口。 功能表现:不仅支持扫描实物二维码,还支持从手机相册里直接读取生成的二维码图片,还支持小程序码扫描,支持查看页面路径和scene值。 结果反馈:系统不会触发自动跳转,而是将二维码包含的原始文本、URL、一维码内容直接以纯文本的形式展示在屏幕上。 价值:多看一眼,少出一次错 现在,每当我生成一个新的二维码,无论是用于软件下载、文档分享还是活动跳转,我都会习惯性地用自己的工具“扫一下”: 确认 URL 参数是否完整。 确认是否有肉眼难以察觉的拼写错误。 确认二维码的类型(一维码还是二维码)是否符合预期。 技术实现 使用小程序纯原生实现,仅仅做一个页面展示即可。 scanQRCode: function () { const that = this; wx.showLoading({ title: '识别中...', mask: true, }) wx.scanCode({ onlyFromCamera: false, scanType: ['qrCode', 'barCode', 'datamatrix', 'pdf417', 'wxCode'], success: (res) => { wx.hideLoading() if(res.scanType=='WX_CODE'){ that.setData({ scanResult: res.path }); }else{ that.setData({ scanResult: res.result }); } }, fail: (err) => { wx.hideLoading() console.error(err); } }); }, 需要注意的是,小程序码和其它码的结果字段有点不同,所以需要区分,以便取到正确的值。 ...

2018-01-09 · 1 min · Eagle