首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >0 元给网站接入微信扫码登录,用小程序就够了~

0 元给网站接入微信扫码登录,用小程序就够了~

作者头像
co松柏
发布2026-07-29 14:29:36
发布2026-07-29 14:29:36
2250
举报

✨ 前言

Hi,我是松柏。

AI 时代,大家或多或少都有了一些做网站的能力。

不知道大家有没有尝试过给自己的网站增加一个登录功能呢?比如微信扫码登录。

我最近就在给我的网站增加微信扫码登录能力。

但经过一番调研发现,微信官方的扫码登录方案要么要营业执照,要么每年交 300 块认证费。

我这个简单的小项目犯不着搞这些复杂的东西。

最终经过一番查找,我发现用微信小程序就能完美绕过这些限制。

效果就是网站弹出一个小程序码:

手机微信扫一扫,网页端自动登录:

点赞关注,接下来我们就一起看看如何实现吧~

其他方案的限制

在开始之前,先来看下主流方案的对比表格:

方案

前置条件

费用

体验

微信开放平台(网站应用)

企业营业执照 + 开发者资质认证

300 元(一次性)

最标准,扫码直接授权

公众号扫码登录

认证服务号

300 元/年

扫码关注后登录

小程序

个人实名即可注册

0 元

扫码进小程序,确认后登录

  • 其实微信开放平台是最正统的方案,用户扫码后直接在微信里弹授权确认,体验也最丝滑。但它要企业资质,个人开发者压根注册不了
  • 公众号方案则需要认证服务号,一年 300,而且还得先有个公司主体
  • 而小程序方案只需要个人身份证实名注册,不需要花一分钱就能搞定

小程序不认证的代价是不能被搜索、不能开通支付、也不能被分享。但咱们就是拿它做个登录跳板,用户只通过扫码进入,完全不需要这些功能。

原理:一码扫完,网页怎么就登录了?

整体流程大概是这样:

ChatGPT Image 2026年7月20日 19_58_38
ChatGPT Image 2026年7月20日 19_58_38

简单看下核心步骤:

  1. ticket 是中转凭证,每次打开登录弹窗生成一个随机 ticket(32 位 hex),存到 Redis,设 5 分钟过期
  2. 小程序码通过 getwxacodeunlimit 接口生成,scene 字段里塞的就是 ticket,用户扫码后小程序从 scene 里取出来
  3. 小程序端调 wx.login() 拿到 code,连同 ticket 一起发给后端,后端用 code 调微信的 code2session 接口换到 openid,完成用户身份绑定
  4. 网页每隔 1~2 秒请求后端“这个 ticket 登录了没”,一旦后端标记成功,前端拿到登录态,弹窗关闭

核心就是,通过小程序从微信获取唯一标识,绑定到我们的网站里,实现一个唯一标识(微信号)对应一个用户。

有个细节得说明一下,小程序从微信获取到的唯一标识叫 openid,openid 只在一个应用里唯一。 什么意思呢? 就是说,假如一个用户在我的小程序里的 openid 是 123,那么我的小程序里不会有其他用户的 openid 是 123 了,但是不影响别人的小程序里有用户的 openid 是 123。

动手实现

1)注册个人小程序

去微信公众平台注册一个小程序账号,只需要实名 + 微信扫码验证就可以了:

注册完拿到 AppID 和 AppSecret,后面要用。

后端实现

这里用 Node.js 示例,其他语言同理。

生成 ticket + 小程序码:

代码语言:javascript
复制
// POST /api/auth/qr/create
async function createQrLogin() {
  const ticket = crypto.randomBytes(16).toString('hex') // 32位 hex
  
  // 存 Redis,5 分钟过期
  await redis.set(`login:${ticket}`, JSON.stringify({ status: 'pending' }), 'EX', 300)
  
  // 调微信接口生成小程序码
  const accessToken = await getAccessToken(APP_ID, APP_SECRET)
  const res = await fetch(
    `https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=${accessToken}`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        scene: ticket,
        page: 'pages/login/login', // 小程序里的登录确认页
        check_path: false,
        width: 280,
      }),
    }
  )
  
  const imageBuffer = await res.arrayBuffer()
  return { ticket, qrcode: Buffer.from(imageBuffer).toString('base64') }
}

这里有三个关键点:

  1. scene 最长只能 32 个可见字符,所以用 16 字节 hex 刚好
  2. check_path: false 让生成码时不校验页面是否已上线,方便开发阶段调试
  3. 返回的是图片二进制,转 base64 给前端展示

轮询状态接口:

代码语言:javascript
复制
// GET /api/auth/qr/status?ticket=xxx
async function checkStatus(ticket: string) {
  const data = await redis.get(`login:${ticket}`)
  if (!data) return { status: 'expired' }
  
  const { status, token } = JSON.parse(data)
  if (status === 'confirmed') {
    await redis.del(`login:${ticket}`) // 一次性,用完删掉
    return { status: 'confirmed', token }
  }
  return { status: 'pending' }
}

确认登录接口(给小程序调的):

代码语言:javascript
复制
// POST /api/auth/mini/confirm
async function confirmLogin(ticket: string, code: string) {
  // 1. 校验 ticket 存在且未过期
  const data = await redis.get(`login:${ticket}`)
  if (!data) throw new Error('二维码已过期')
  
  // 2. 用 code 换 openid
  const session = await code2Session(APP_ID, APP_SECRET, code)
  const { openid } = session
  
  // 3. 查找或创建用户,生成登录 token
  const user = await findOrCreateUser(openid)
  const token = generateToken(user)
  
  // 4. 更新 ticket 状态
  await redis.set(`login:${ticket}`, JSON.stringify({ status: 'confirmed', token }), 'EX', 60)
  
  return { success: true }
}

code2Session 就是调微信的 https://api.weixin.qq.com/sns/jscode2session,传 appid、secret、js_code,换回 openid。

小程序侧

小程序只需要一个"登录确认页",用户扫码后会自动跳到这个页面。

代码语言:javascript
复制
// pages/login/login.js
Page({
  onLoad(options) {
    // 从小程序码的 scene 里取 ticket
    const ticket = decodeURIComponent(options.scene || '')
    if (!ticket) {
      wx.showToast({ title: '二维码无效', icon: 'error' })
      return
    }
    this.confirmLogin(ticket)
  },

  async confirmLogin(ticket) {
    try {
      // 1. wx.login 拿 code
      const { code } = await wx.login()
      
      // 2. 请求你的后端 confirm 接口
      const res = await wx.request({
        url: `https://your-domain.com/api/auth/mini/confirm`,
        method: 'POST',
        data: { ticket, code },
      })
      
      if (res.data.success) {
        wx.showToast({ title: '登录成功', icon: 'success' })
        setTimeout(() => wx.navigateBack(), 1500)
      }
    } catch (err) {
      wx.showToast({ title: '登录失败', icon: 'error' })
    }
  },
})

页面 UI 可以做得简单一点:显示个 loading 动画 + "正在确认登录..."的文案就行,用户感知上就是扫完码等一秒就好了。

前端:展示二维码 + 轮询

代码语言:javascript
复制
// 伪代码,React 示例
function LoginModal() {
  const [qrcode, setQrcode] = useState('')
  const [ticket, setTicket] = useState('')

  useEffect(() => {
    // 请求后端生成小程序码
    fetch('/api/auth/qr/create', { method: 'POST' })
      .then(res => res.json())
      .then(({ ticket, qrcode }) => {
        setTicket(ticket)
        setQrcode(qrcode)
      })
  }, [])

  useEffect(() => {
    if (!ticket) return
    // 每 1.5 秒轮询
    const timer = setInterval(async () => {
      const res = await fetch(`/api/auth/qr/status?ticket=${ticket}`)
      const data = await res.json()
      if (data.status === 'confirmed') {
        clearInterval(timer)
        // 拿到 token,登录成功!
        login(data.token)
      } else if (data.status === 'expired') {
        clearInterval(timer)
        // 提示过期,让用户刷新
      }
    }, 1500)
    return () => clearInterval(timer)
  }, [ticket])

  return (
    <div>
      <img src={`data:image/png;base64,${qrcode}`} />
      <p>请用微信扫一扫</p>
    </div>
  )
}

注意事项 & 踩坑

scene 只有 32 字符。不要想着往里塞 JWT 或者 URL,只放一个 ticket ID 就行,其他信息让后端通过 ticket 去 Redis 里查。

小程序必须已发布getwxacodeunlimit 生成的码指向的是正式版小程序。如果你的登录页还没发布上线,用户扫了会报"页面不存在"。开发阶段可以设 check_path: false 先把码生成出来,但真机测试还是得至少上个体验版。

本地调试怎么搞? 不需要真机扫码。在微信开发者工具里添加一个编译模式,启动页面填 pages/login/login,启动参数填 scene=你的ticket,就能模拟扫码进入的效果。

真机测试走局域网。手机访问不了你电脑的 localhost,小程序里的 API 地址要改成你电脑的局域网 IP(比如 192.168.1.8:3000),同时开发者工具里关掉"域名校验"。

access_token 要缓存。微信的 access_token 有效期 2 小时,别每次生成码都重新获取,用 Redis 缓存一下。

🎯 结语

总结一下:个人开发者想给网站加微信扫码登录,不用花钱、不用营业执照,注册一个个人主体的小程序就够了。核心就是 getwxacodeunlimit + wx.login + 一个 Redis ticket,整套逻辑并不复杂。

下期再见,拜拜👋🏻

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-28,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • ✨ 前言
  • 其他方案的限制
  • 原理:一码扫完,网页怎么就登录了?
  • 动手实现
    • 后端实现
    • 小程序侧
    • 前端:展示二维码 + 轮询
  • 注意事项 & 踩坑
  • 🎯 结语
相关产品与服务
云开发 CloudBase
AI-Native 的全栈应用开发平台,为 AI 驱动的开发流程和终端应用而设计。提供应用开发所需的完整 Serverless 资源,包括身份认证、数据库、云函数与容器、文件存储、Web 应用托管等能力;支持小程序/小游戏、AI Agent 应用、Web 应用等场景;提供 Skills/MCP 工具适配主流 AI 编程工具,避免了开发过程中繁琐的服务端搭建及运维,开发者可以专注于业务逻辑的实现,开发效率更高。
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档