前端实现 PC 网站微信扫码授权登录
PC 端微信扫码授权登录基于 Vue 3 和 Element Plus 实现,涵盖手机号验证码登录、微信直接扫码及二次绑定三种场景。核心流程涉及微信 SDK 初始化、二维码生成、回调参数处理及状态管理。通过 Pinia 存储 Token 和用户信息,结合路由守卫控制访问权限,确保登录安全与用户体验。

PC 端微信扫码授权登录基于 Vue 3 和 Element Plus 实现,涵盖手机号验证码登录、微信直接扫码及二次绑定三种场景。核心流程涉及微信 SDK 初始化、二维码生成、回调参数处理及状态管理。通过 Pinia 存储 Token 和用户信息,结合路由守卫控制访问权限,确保登录安全与用户体验。

本项目是一个基于 Vue 3 + Element Plus 的 AI 汽配查询系统,需要实现 PC 端微信扫码授权登录功能。用户可以通过手机号验证码登录,也可以通过微信扫码快速登录,实现账号与微信的绑定。
<!-- 微信登录 JS SDK -->
<script src="https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>

┌─────────────┐
│ 登录页面 │
│ /login │
└──────┬──────┘
│
├────────────┬────────────┐
│ │ │
▼ ▼ ▼
手机号登录 微信扫码 已有账号
│ │ │
▼ ▼ ▼
发送验证码 扫码授权 直接登录
│ │ │
▼ ▼ ▼
验证码登录 ───┘ ┌─────────┐
│ 首页 │
│ /home │
└─────────┘
code=506?
┌┴┐
是 │否
▼ ▼
需要绑定 登录成功
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│微信授权 │ │ 首页 │
│ /weChat │ │ /home │
└────┬────┘ └─────────┘
│
▼
扫码授权
│
▼
┌─────────────┐
│ 回调页面 │
│ /callback │
└──────┬──────┘
│
├────────────┬────────────┐
│ │ │
state=wx_bind state=wechat_login
▼ ▼
首次绑定 二次授权
│ │
┌┴┐ │
是 │否 │
▼ ▼ ▼ │
code=405 登录成功 绑定成功
│ │
▼ ▼
┌─────────┐ ┌──────────┐
│绑定手机号│ │ 首页 │
│/mobilePhone│ │ /home │
└─────────┘ └──────────┘
/weChat 页面扫码绑定/callback 页面,state=wx_bind/mobilePhone/weChat 页面/callback 页面// 微信登录实例
let wxLoginInstance = null;
// 初始化微信授权登录
const initWechatLogin = () => {
try {
createWxLogin();
console.log("微信授权登录初始化成功");
} catch (error) {
console.error("微信授权登录初始化失败:", error);
ElMessage.error("微信授权登录初始化失败");
}
};
// 创建微信登录二维码
const createWxLogin = () => {
try {
// 自定义 CSS 样式,隐藏多余元素
const customCss = `
.impowerBox {display:block!important;visibility:visible!important;...}
.impowerBox .qrcode {display:block!important;...}
.impowerBox .title {display:none!important}
.info {display:none!important}
`;
const href = 'data:text/css;base64,' + btoa(customCss);
const appid = "xxxxxxx";
// 公网回调地址
const redirectUri = encodeURIComponent("https://xxxxx.com/callback");
const state = "wx_bind"; // 标识为首次绑定场景
// 使用微信官方 WxLogin 对象
wxLoginInstance = new window.WxLogin({
self_redirect: false,
id: "wechat-login-qr",
appid: appid,
: ,
: redirectUri,
: state,
: href
});
.();
} (error) {
.(, error);
.();
}
};
( {
( {
();
}, );
});
( {
(wxLoginInstance) {
wxLoginInstance = ;
}
container = .();
(container) {
container. = ;
}
});
const account = ref("");
const verifyCode = ref("");
const countdown = ref(0);
// 手机号格式验证
const validatePhone = (phone) => {
const phoneRegex = /^1[3-9]\d{9}$/;
return phoneRegex.test(phone);
};
// 发送验证码
const sendCode = async () => {
if (countdown.value > 0) return;
if (!account.value) {
ElMessage.warning("请输入手机号");
return;
}
if (!validatePhone(account.value)) {
ElMessage.warning("请输入正确的 11 位手机号");
return;
}
// 启动倒计时
countdown.value = 60;
const timer = setInterval(() => {
countdown.value--;
if (countdown.value <= 0) {
clearInterval(timer);
}
}, 1000);
// 调用发送验证码接口
const { code, msg } = (account.);
(code !== ) {
.(msg);
} {
(msg) {
verifyCode. = msg;
.();
}
}
};
= () => {
(!account. || !(account.)) {
.();
;
}
(!verifyCode.) {
.();
;
}
{ code, msg, data } = (account., verifyCode.);
(code === ) {
loginStore.(account.);
.();
router.();
;
}
(code !== ) {
.(msg);
;
}
loginStore.(data.);
loginStore.(data.);
chatStore.();
.();
router.();
};
// 微信登录实例
let wxLoginInstance = null;
// 创建微信绑定二维码
const createWxBind = () => {
try {
const container = document.getElementById('wechat-bind-qr');
if (container) {
container.innerHTML = '';
}
// 自定义样式
const customCss = `...`;
const href = 'data:text/css;base64,' + btoa(customCss);
const appid = "xxxx";
const redirectUri = encodeURIComponent("https://xxx/callback");
const state = "wechat_login"; // 标识为二次授权场景
wxLoginInstance = new window.WxLogin({
self_redirect: false,
id: "wechat-bind-qr",
appid: appid,
scope: "snsapi_login",
redirect_uri: redirectUri,
state: state, // 与登录页的 state 不同
href: href
});
console.log("微信绑定二维码已生成,等待用户扫码...");
} catch (error) {
console.error("创建微信绑定二维码失败:", error);
}
};
= () => {
e.();
e.();
router.();
};
这是整个流程中最核心的部分,负责处理微信授权回调。
const loading = ref(true);
const statusText = ref("正在处理微信授权...");
onMounted(async () => {
try {
// 获取 URL 参数
const code = route.query.code; // 微信授权码
const state = route.query.state; // 场景标识
console.log("微信回调参数:", { code, state });
if (!code) {
throw new Error("未获取到授权码");
}
// 存储 code 到 pinia
loginStore.setWechatLoginCode(code);
// ========== 场景 1: 从登录页直接扫码 (wx_bind) ==========
if (state === 'wx_bind') {
statusText.value = "正在检查登录状态...";
// 调用后端接口检查微信登录状态
const { data, code: resultCode, msg } = await checkWechatLoginStatusAPI(code, state);
// 情况 1: 需要绑定手机号 (新用户)
if (resultCode === 405) {
statusText.value = "需要绑定手机号,正在跳转...";
loading.value = false;
ElMessage.info("请先绑定手机号");
setTimeout(() => {
router.();
}, );
;
}
{
loginStore.(data.);
loginStore.(data.);
chatStore.();
statusText. = ;
loading. = ;
.();
( {
router.();
}, );
;
}
}
(state === ) {
statusText. = ;
phone = loginStore.;
(!phone) {
();
}
result = (code, phone);
(result. === ) {
loginStore.(result..);
loginStore.(result..);
chatStore.();
statusText. = ;
loading. = ;
.();
( {
router.();
}, );
;
} {
(result. || );
}
}
} (error) {
.(, error);
statusText. = ;
loading. = ;
.();
( {
router.();
}, );
}
});
import request from "../utils/request";
/**
* 发送验证码接口
*/
export const sendCodeAPI = (phone) => {
return request({
url: `/client/code/send-sms?phone=${phone}`,
method: "get",
});
};
/**
* 登录接口
* @param {string} phoneNumber - 手机号
* @param {string} code - 验证码
* @param {number} registerType - 注册类型,0 表示 PC 端
*/
export const loginAPI = (phoneNumber, code, registerType = 0) => {
return request({
url: `/client/customer/login-by-code`,
method: "post",
data: {
phoneNumber,
code,
registerType,
},
});
};
/**
* 检查微信登录状态
* @param {string} code - 微信授权码
* @param {string} state - 场景标识
*/
export const checkWechatLoginStatusAPI = (code, state) => {
return request({
url: `/client/customer/check-is-success?code=&state=`,
: ,
});
};
= () => {
({
: ,
: ,
});
};
= () => {
({
: ,
: ,
: {
phoneNumber,
phoneCode,
code,
},
});
};
import { defineStore } from "pinia";
import { ref } from "vue";
export const useLoginStore = defineStore("login", () => {
// 存储 token
const token = ref("");
const setToken = (value) => {
token.value = value;
};
// 存储用户信息
const userInfo = ref({});
const setUserInfo = (value) => {
userInfo.value = value;
};
// 存储微信登录 code
const wechatLoginCode = ref("");
const setWechatLoginCode = (value) => {
wechatLoginCode.value = value;
};
// 存储手机号(用于二次授权)
const phone = ref("");
const setPhone = (value) => {
phone.value = value;
};
return {
token,
setToken,
userInfo,
setUserInfo,
wechatLoginCode,
setWechatLoginCode,
phone,
setPhone,
};
}, { persist: true }); // 持久化存储
import { createRouter, createWebHistory } from "vue-router";
import { useLoginStore } from "@/stores/modules/login";
const routes = [
{
path: "/login",
name: "login",
component: () => import("../views/Login/index.vue"),
},
{
path: "/home",
name: "home",
component: () => import("../views/Home/index.vue"),
meta: { requiresAuth: true }, // 需要登录
},
{
path: "/callback",
name: "callback",
component: () => import("../views/callback/index.vue"),
},
{
path: "/weChat",
name: "weChat",
component: () => import("../views/weChat/index.vue"),
},
{
path: "/mobilePhone",
name: "mobilePhone",
component: () => import("../views/mobilePhone/index.vue"),
},
];
const router = ({
: (...),
routes,
});
router.( {
loginStore = ();
token = loginStore.;
(to..) {
(!token) {
.();
();
;
}
}
(to. === && token) {
.();
();
;
}
();
});
router;

本文详细介绍了 PC 端微信扫码授权登录的完整实现方案,包括:
这套方案已在生产环境稳定运行,具有很好的参考价值。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online