稀土掘金技术社区

前端对接微信扫码登录:从踩坑到填坑的全记录

(💰金石瓜分计划回归,速戳下图了解详情🔍)图片

作为一名刚接触第三方登录的前端开发,当我接到 "对接微信扫码登录" 需求时,内心是崩溃的——毕竟平时连公众号都没运营过。经过两周的折腾,终于从一脸懵逼到勉强跑通流程,现在把这段 "血泪史" 整理成指南,希望能帮到同样迷茫的你。

一、前期准备:少走弯路的 checklist

1. 必备材料清单

  • [x]  「微信开放平台账号」(个人 / 企业均可,企业需认证)
  • [x]  「网站域名」(必须备案!测试环境可用localhost但有限制)
  • [x]  「服务器 IP 白名单」(在开放平台配置)
  • [ ]  300 元认证费(企业账号必须,个人开发可跳过)
❝

💡 「血泪教训」:我曾在凌晨 2 点发现测试环境扫码失败,原因竟是没加 IP 白名单!

❞

2. 创建网站的 "身份证"

  1. 登录微信开放平台[1]

  2. 进入 "网站应用" → "创建网站应用"

  3. 填写关键信息:

    应用名称:我的Awesome网站
    域名:www.yourdomain.com
    回调域名:www.yourdomain.com/auth/wechat


二、开发实战:前端代码的奇幻漂流

1. 引入官方 JS-SDK(踩坑预警!)

<!-- 官方推荐方式 -->
<script src="https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>

<!-- 我的改良方案(避免CDN加载失败) -->
<script>
  function loadWXSDK() {
    return new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = 'https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js'
      script.onload = resolve
      script.onerror = () => reject(new Error('微信SDK加载失败'))
      document.head.appendChild(script)
    })
  }
</script>


2. 初始化扫码登录(含避坑参数)

async function initWechatLogin() {
  await loadWXSDK()

  new WxLogin({
    self_redirect: true, // 重要!true时自动跳转,false用iframe嵌入
    id: "wechat-login-container", 
    appid: "你的appid", // 注意不是公众号ID!
    scope: "snsapi_login", // 固定值不要改
    redirect_uri: encodeURIComponent("https://www.yourdomain.com/auth/wechat"),
    state: "随机防CSRF字符串", // 建议用uuid生成
    style: "black", // 黑白主题可选
    href: "" // 自定义CSS样式URL(跨域限制!)
  })
}


3. 处理回调的 "暗礁险滩"

// 回调页面处理逻辑
const parseAuthResponse = () => {
  const hash = window.location.hash.substr(1)
  const params = new URLSearchParams(hash)

  // 微信返回的关键参数
  const accessToken = params.get('access_token')
  const expiresIn = params.get('expires_in')
  const state = params.get('state') // 必须验证与发起时一致!

  if (!accessToken) {
    const errCode = params.get('error')
    showError(`登录失败: ${getErrorMsg(errCode)}`)
    return
  }

  // 换取用户信息(需后端配合)
  fetchUserInfo(accessToken)
}

// 常见错误码处理
const getErrorMsg = (code) => {
  const errors = {
    10003: 'redirect_uri域名与后台配置不一致',
    10004: '此公众号被封禁',
    10005: '此公众号并没有这些scope的权限'
  }
  return errors[code] || `未知错误(code: ${code})`
}


三、那些让我熬夜的深坑实录

1. 域名验证的 "玄学" 问题

「现象」:配置了www.domain.com,但用户用domain.com访问时报错
「解决方案」:

// 前端统一处理域名
const canonicalDomain = 'www.yourdomain.com'
if (location.host !== canonicalDomain) {
  window.location.href = `https://${canonicalDomain}${location.pathname}`
}


2. 移动端的 "幽灵" 问题

「现象」:手机浏览器扫码后无法跳回原页面
「原因」:微信客户端会拦截非白名单域名的跳转
「解决方案」:

// 检测移动端使用备用方案
if (/Mobile|Android|iPhone/i.test(navigator.userAgent)) {
  showQRCodeWithFallback() // 显示带提示的二维码图片
  startPollingAuthResult() // 启用轮询检查登录状态
}


3. 样式自定义的 "铁壁" 限制

「需求」:想改二维码按钮样式
「现实」:微信不允许直接修改,但可以:

/* 曲线救国方案 */
#wechat-login-container iframe {
  transform: scale(1.2); /* 缩放二维码 */
  pointer-events: none; /* 穿透点击事件 */
}

/* 添加自定义UI层 */
.qr-mask {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  /* 用伪元素实现自定义样式 */
}


四、安全加固:从入门到防御

1. State 参数防 CSRF

// 生成state
const generateState = () => {
  return [
    Date.now().toString(36),
    Math.random().toString(36).substr(2),
    window.crypto.getRandomValues(new Uint8Array(3))[0].toString(36)
  ].join('-')
}

// 验证state(回调页面)
const isValidState = (receivedState) => {
  const savedState = sessionStorage.getItem('wx_state')
  return receivedState === savedState
}


2. Token 安全处理

// 正确姿势
const handleToken = (token) => {
  // 1. 立即清除URL中的token
  window.history.replaceState({}, '', window.location.pathname)

  // 2. 存储到HttpOnly Cookie
  document.cookie = `auth_token=${token}; Path=/; Secure; SameSite=Strict`

  // 3. 避免XSS泄露
  window.__PRIVATE_TOKEN__ = undefined // 清除内存引用
}


五、性能优化实战

1. 延迟加载策略

// 用户点击登录按钮再加载
document.getElementById('wechat-login-btn').addEventListener('click', () => {
  import('./wechatAuth.js').then(module => {
    module.initWechatLogin()
  })
}, { once: true })


2. 多实例问题解决

// 防止重复初始化
let wxLoginInstance = null

function safeInitWechatLogin() {
  if (!wxLoginInstance) {
    wxLoginInstance = new WxLogin({/* 配置 */})
  }
  return wxLoginInstance
}


六、终极调试技巧

1. 本地开发解决方案

# 修改/etc/hosts
127.0.0.1   test.yourdomain.com


// 开发环境特殊处理
if (process.env.NODE_ENV === 'development') {
  window.__wxjs_is_wkwebview = true // 解决iOS调试问题
}


2. 真机调试工具

  • 「微信开发者工具」:模拟扫码登录流程
  • 「Charles 抓包」:分析微信跳转过程
  • 「Eruda」:移动端 Console 调试

七、我的学习路线图

  1. 微信开放平台文档[2](必读三遍)
  2. OAuth2.0 协议[3](理解底层原理)
  3. SameSite Cookie 详解[4](解决跨域问题)

最后给所有对接第三方登录的同行一个忠告:「永远要有 Plan B」!我在项目上线当天遇到微信服务波动,临时增加了 "账号密码 + 短信验证码" 的备用方案,成功避免了一场事故。记住:用户不会关心是谁的接口挂了,他们只会觉得是你的网站有问题!


关注更多AI编程资讯请去AI Coding专区:https://juejin.cn/aicoding