欢迎光临
我们一直在努力

前端实现PC网站微信扫码授权登陆

文章目录

  • PC端微信扫码授权登录技术实现分享
    • 一、项目背景
    • 二、技术架构
      • 2.1 技术栈
      • 2.2 核心依赖
    • 三、功能流程设计
      • 3.1 整体流程图
      • 3.2 三种登录场景
        • 场景1: 手机号 + 验证码登录
        • 场景2: 微信直接扫码登录(已绑定)
        • 场景3: 微信二次授权绑定(未绑定)
    • 四、核心代码实现
      • 4.1 登录页面实现 (Login/index.vue)
        • 4.1.1 微信二维码初始化
        • 4.1.2 手机号登录逻辑
      • 4.2 微信授权绑定页面 (weChat/index.vue)
      • 4.3 回调页面处理 (callback/index.vue)
      • 4.4 API接口封装 (apis/user.js)
      • 4.5 状态管理 (stores/modules/login.js)
      • 4.6 路由守卫配置 (router/index.js)
    • 总结

PC端微信扫码授权登录技术实现分享

一、项目背景

本项目是一个基于 Vue 3 + Element Plus 的 AI 汽配查询系统,需要实现PC端微信扫码授权登录功能。用户可以通过手机号验证码登录,也可以通过微信扫码快速登录,实现账号与微信的绑定。

二、技术架构

2.1 技术栈

  • 前端框架: Vue 3 (Composition API)
  • UI组件库: Element Plus
  • 状态管理: Pinia
  • 路由管理: Vue Router
  • HTTP请求: Axios (封装)
  • 微信SDK: 微信开放平台 JS SDK

2.2 核心依赖

<! 微信登录 JS SDK >
<script src="https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>

在这里插入图片描述

三、功能流程设计

3.1 整体流程图

┌─────────────┐
│ 登录页面 │
/login │
└──────┬──────┘

├────────────┬────────────┐
│ │ │
▼ ▼ ▼
手机号登录 微信扫码 已有账号
│ │ │
▼ ▼ ▼
发送验证码 扫码授权 直接登录
│ │ │
▼ │ ▼
验证码登录 ───┘ ┌─────────┐
│ │ 首页 │
▼ │ /home │
code=506? └─────────┘

┌────┴────┐
│是 │否
▼ ▼
需要绑定 登录成功
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│微信授权 │ │ 首页 │
/weChat │ │ /home │
└────┬────┘ └─────────┘


扫码授权


┌─────────────┐
│ 回调页面 │
/callback │
└──────┬───────┘

├────────────┬────────────┐
│ │ │
state=wx_bind state=wechat_login
│ │
▼ ▼
首次绑定 二次授权
│ │
┌────┴────┐ │
│是 │否 │
▼ ▼ ▼
code=405 登录成功 绑定成功
│ │ │
▼ ▼ ▼
┌─────────┐ ┌──────────┐
│绑定手机号│ │ 首页 │
/mobilePhone│ /home │
└─────────┘ └──────────┘

3.2 三种登录场景

场景1: 手机号 + 验证码登录
  • 用户输入手机号
  • 点击发送验证码(60s倒计时)
  • 输入验证码并登录
  • 后端返回 code=506 → 需要微信授权绑定
  • 跳转到 /weChat 页面扫码绑定
  • 场景2: 微信直接扫码登录(已绑定)
  • 登录页右侧展示微信二维码
  • 用户扫码授权
  • 回调到 /callback 页面,state=wx_bind
  • code=200 → 登录成功,跳转首页
  • code=405 → 需要绑定手机号,跳转 /mobilePhone
  • 场景3: 微信二次授权绑定(未绑定)
  • 从手机号登录后需要绑定(code=506)
  • 跳转到 /weChat 页面
  • 扫码授权,state=wechat_login
  • 回调到 /callback 页面
  • 调用绑定接口,登录成功
  • 四、核心代码实现

    4.1 登录页面实现 (Login/index.vue)

    4.1.1 微信二维码初始化

    // 微信登录实例
    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", // 容器ID
    appid: appid,
    scope: "snsapi_login", // 授权作用域
    redirect_uri: redirectUri,
    state: state,
    href: href // 自定义样式
    });

    console.log("微信二维码已生成,等待用户扫码…");
    } catch (error) {
    console.error("创建微信登录二维码失败:", error);
    ElMessage.error("创建微信登录二维码失败");
    }
    };

    // 页面挂载时初始化
    onMounted(() => {
    setTimeout(() => {
    initWechatLogin();
    }, 100);
    });

    // 页面卸载时清理
    onUnmounted(() => {
    if (wxLoginInstance) {
    wxLoginInstance = null;
    }
    const container = document.getElementById('wechat-login-qr');
    if (container) {
    container.innerHTML = '';
    }
    });

    4.1.2 手机号登录逻辑

    const account = ref("");
    const verifyCode = ref("");
    const countdown = ref(0);

    // 手机号格式验证
    const validatePhone = (phone) => {
    const phoneRegex = /^1[39]\\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 } = await sendCodeAPI(account.value);
    if (code !== 200) {
    ElMessage.error(msg);
    } else {
    if (msg) {
    verifyCode.value = msg; // 开发环境自动填入
    ElMessage.success("验证码已自动填入");
    }
    }
    };

    // 登录处理
    const handleLogin = async () => {
    // 表单验证
    if (!account.value || !validatePhone(account.value)) {
    ElMessage.warning("请输入正确的手机号");
    return;
    }
    if (!verifyCode.value) {
    ElMessage.warning("请输入验证码");
    return;
    }

    // 调用登录接口
    const { code, msg, data } = await loginAPI(account.value, verifyCode.value);

    // 检查是否需要微信授权绑定
    if (code === 506) {
    loginStore.setPhone(account.value); // 存储手机号
    ElMessage.info("需要进行微信授权绑定");
    router.push("/weChat");
    return;
    }

    if (code !== 200) {
    ElMessage.error(msg);
    return;
    }

    // 登录成功,存储token和用户信息
    loginStore.setToken(data.token);
    loginStore.setUserInfo(data.information);
    chatStore.clearChatData(); // 重置聊天状态

    ElMessage.success("登录成功");
    router.replace("/home");
    };

    4.2 微信授权绑定页面 (weChat/index.vue)

    // 微信登录实例
    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);
    }
    };

    // 返回登录
    const backToLogin = (e) => {
    e.preventDefault();
    e.stopPropagation();
    router.push("/login");
    };

    4.3 回调页面处理 (callback/index.vue)

    这是整个流程中最核心的部分,负责处理微信授权回调。

    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.replace("/mobilePhone");
    }, 1000);
    return;
    }
    // 情况2: 已绑定,直接登录成功
    else {
    loginStore.setToken(data.token);
    loginStore.setUserInfo(data.information);
    chatStore.clearChatData();

    statusText.value = "微信绑定处理完成";
    loading.value = false;
    ElMessage.success("微信绑定成功");

    setTimeout(() => {
    router.replace("/home");
    }, 1000);
    return;
    }
    }

    // ========== 场景2: 从weChat页面二次授权 (wechat_login) ==========
    if (state === 'wechat_login') {
    statusText.value = "正在进行微信二次授权…";

    // 从pinia中获取phone(之前手机号登录时存储的)
    const phone = loginStore.phone;
    if (!phone) {
    throw new Error("未找到手机号信息,请重新登录");
    }

    // 调用微信绑定接口
    const result = await bindWechatAPI(code, phone);

    if (result.code === 200) {
    loginStore.setToken(result.data.token);
    loginStore.setUserInfo(result.data.information);
    chatStore.clearChatData();

    statusText.value = "微信授权成功,正在跳转…";
    loading.value = false;
    ElMessage.success("微信授权成功");

    setTimeout(() => {
    router.replace("/home");
    }, 1000);
    return;
    } else {
    throw new Error(result.msg || "微信授权失败");
    }
    }

    } catch (error) {
    console.error("微信授权处理失败:", error);
    statusText.value = "授权失败";
    loading.value = false;
    ElMessage.error("授权处理失败,请重试");

    setTimeout(() => {
    router.replace("/login");
    }, 2000);
    }
    });

    4.4 API接口封装 (apis/user.js)

    import request from "../utils/request";

    /**
    * 发送验证码接口
    */

    export const sendCodeAPI = (phone) => {
    return request({
    url: `/client/code/sendsms?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/loginbycode`,
    method: "post",
    data: { phoneNumber, code, registerType },
    });
    };

    /**
    * 检查微信登录状态
    * @param {string} code – 微信授权码
    * @param {string} state – 场景标识
    */

    export const checkWechatLoginStatusAPI = (code, state) => {
    return request({
    url: `/client/customer/checkissuccess?code=${code}&state=${state}`,
    method: "get",
    });
    };

    /**
    * 绑定微信(二次授权)
    * @param {string} code – 微信授权码
    * @param {string} phone – 手机号
    */

    export const bindWechatAPI = (code, phone) => {
    return request({
    url: `/client/customer/checkwechat?code=${code}&phone=${phone}`,
    method: "GET",
    });
    };

    /**
    * 绑定手机号
    * @param {string} phoneNumber – 手机号
    * @param {string} phoneCode – 手机验证码
    * @param {string} code – 微信登录code
    */

    export const bindPhoneAPI = (phoneNumber, phoneCode, code) => {
    return request({
    url: `/client/customer/checkphone`,
    method: "POST",
    data: { phoneNumber, phoneCode, code },
    });
    };

    4.5 状态管理 (stores/modules/login.js)

    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, // 持久化存储
    }
    );

    4.6 路由守卫配置 (router/index.js)

    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 = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes,
    });

    // 全局前置守卫
    router.beforeEach((to, from, next) => {
    const loginStore = useLoginStore();
    const token = loginStore.token;

    // 需要登录的页面
    if (to.meta.requiresAuth) {
    if (!token) {
    console.log('用户未登录,重定向到登录页面');
    next('/login');
    return;
    }
    }

    // 已登录用户访问登录页,重定向到首页
    if (to.path === '/login' && token) {
    console.log('用户已登录,重定向到首页');
    next('/');
    return;
    }

    next();
    });

    export default router;

    在这里插入图片描述

    总结

    本文详细介绍了PC端微信扫码授权登录的完整实现方案,包括:

  • ✅ 完整的业务流程: 涵盖手机号登录、微信直接登录、二次授权三种场景
  • ✅ 详细的代码实现: 从初始化到回调处理的每个环节
  • ✅ 丰富的技术细节: 状态管理、路由守卫、样式定制等
  • ✅ 实用的优化方案: 用户体验、性能、安全性多方面考虑
  • ✅ 常见问题解决: 总结实际开发中遇到的坑和解决方案
  • 这套方案已在生产环境稳定运行,具有很好的参考价值。希望能帮助你快速实现类似的功能!


    项目技术栈: Vue 3 + Pinia + Vue Router + Element Plus + 微信开放平台 JS SDK 适用场景: PC端需要集成微信扫码登录的项目 难度等级: ⭐⭐⭐⭐ (中高级)

    如有疑问,欢迎交流讨论! 🚀

    赞(0)
    未经允许不得转载:171主机测评 » 前端实现PC网站微信扫码授权登陆
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址