news 2026/2/23 14:21:35

PC 端微信扫码登录实现教程(Java + Vue 2)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PC 端微信扫码登录实现教程(Java + Vue 2)
在 PC 端实现微信扫码登录时,用户用手机微信扫码后,PC 端要能自动登录。本文整理了完整流程,包括前端、后端实现和流程图。

一、核心流程概览

PC 扫码登录本质是通过唯一 sessionId(state)绑定一次扫码会话。流程如下:

PC端 /wechat/login 页面 ↓ 显示二维码 + sessionId 手机微信扫码二维码 ↓ 微信官方授权页面(无需前端实现) ↓ 用户确认授权 微信回调后端 /wechat/callback ↓ 后端用 code 换取 access_token + openid ↓ 后端生成系统 token,并更新 sessionId 状态为 success PC端轮询 /api/wechat/qr/status?sessionId=xxx ↓ 获取 token ↓ 保存 token → 登录成功 → 跳转首页

🔑 要点:

  • sessionId:每次生成二维码唯一标识扫码会话
  • 手机授权页面:微信官方提供,前端无需处理
  • PC 端通过轮询或 WebSocket 查询授权状态

二、前端实现(Vue 2)

1️⃣ 二维码显示页面

WechatLogin.vue

<template> <div class="wechat-login"> <h2>微信扫码登录</h2> <div v-if="qrUrl"> <p>请使用微信扫码登录</p> <img :src="qrUrl" alt="微信扫码登录二维码" /> </div> <div v-else> <p>二维码生成中...</p> </div> </div> </template> <script> import axios from 'axios'; export default { data() { return { qrUrl: '', }; }, mounted() { this.fetchQrCode(); }, methods: { async fetchQrCode() { try { const res = await axios.get('/api/wechat/qr'); this.qrUrl = res.data.qrUrl; // 获取二维码 URL 中的 sessionId const sessionId = new URL(this.qrUrl).searchParams.get('state'); this.startPolling(sessionId); } catch (err) { console.error('生成二维码失败', err); } }, startPolling(sessionId) { const interval = setInterval(async () => { const res = await axios.get(`/api/wechat/qr/status?sessionId=${sessionId}`); if (res.data.status === 'success') { clearInterval(interval); localStorage.setItem('token', res.data.token); window.location.href = '/'; } else if (res.data.status === 'failed' || res.data.status === 'expired') { clearInterval(interval); alert('扫码登录失败或二维码过期,请重新扫码'); } }, 2000); } } }; </script> <style scoped> .wechat-login { text-align: center; padding: 50px; } .wechat-login img { width: 250px; height: 250px; } </style>

前端说明:

  • /api/wechat/qr返回二维码 URL
  • 轮询/api/wechat/qr/status?sessionId=xxx获取授权结果

三、后端实现(Java + Spring Boot)

1️⃣ 数据结构

import java.time.LocalDateTime; public class WechatLoginSession { private String sessionId; private String status; // pending / success / failed private String token; private LocalDateTime expireTime; // getter / setter }
  • 内存 Map保存会话(生产环境可用 Redis)
import java.util.concurrent.ConcurrentHashMap; public class WechatSessionStore { public static final ConcurrentHashMap<String, WechatLoginSession> sessionMap = new ConcurrentHashMap<>(); }

2️⃣ 生成二维码 URL

@GetMapping("/api/wechat/qr") public Map<String, String> getQrCode() throws Exception { String sessionId = UUID.randomUUID().toString(); WechatLoginSession session = new WechatLoginSession(); session.setSessionId(sessionId); session.setStatus("pending"); session.setExpireTime(LocalDateTime.now().plusMinutes(5)); WechatSessionStore.sessionMap.put(sessionId, session); String redirectUriEncoded = URLEncoder.encode("https://yourdomain.com/api/wechat/callback", "UTF-8"); String qrUrl = "https://open.weixin.qq.com/connect/qrconnect?" + "appid=" + APPID + "&redirect_uri=" + redirectUriEncoded + "&response_type=code" + "&scope=snsapi_login" + "&state=" + sessionId + "#wechat_redirect"; return Collections.singletonMap("qrUrl", qrUrl); }

3️⃣ 微信回调处理

@GetMapping("/api/wechat/callback") public String callback(@RequestParam String code, @RequestParam String state) { WechatLoginSession session = WechatSessionStore.sessionMap.get(state); if (session == null) { return "登录会话不存在或已过期"; } try { // 用 code 换取 access_token + openid RestTemplate restTemplate = new RestTemplate(); String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + "appid=" + APPID + "&secret=" + APPSECRET + "&code=" + code + "&grant_type=authorization_code"; Map<String, Object> tokenResp = restTemplate.getForObject(url, Map.class); String openid = (String) tokenResp.get("openid"); // 生成系统 token String systemToken = "token-" + openid + "-" + System.currentTimeMillis(); session.setStatus("success"); session.setToken(systemToken); return "授权成功,请返回 PC 页面"; } catch (Exception e) { e.printStackTrace(); session.setStatus("failed"); return "授权失败"; } }

4️⃣ PC 端轮询接口

@GetMapping("/api/wechat/qr/status") public Map<String, Object> checkQrStatus(@RequestParam String sessionId) { WechatLoginSession session = WechatSessionStore.sessionMap.get(sessionId); if (session == null) { return Map.of("status", "expired"); } if ("success".equals(session.getStatus())) { String token = session.getToken(); WechatSessionStore.sessionMap.remove(sessionId); // 可选移除 return Map.of("status", "success", "token", token); } if ("failed".equals(session.getStatus())) { return Map.of("status", "failed"); } return Map.of("status", "pending"); }

四、流程图

flowchart TD A[PC端请求 /wechat/login] --> B[后端生成二维码 + sessionId] B --> C[前端显示二维码] D[用户用手机扫码] --> E[微信授权页面(微信自带)] E --> F[用户确认授权] F --> G[微信回调后端 /wechat/callback] G --> H[后端换取 access_token + openid] H --> I[后端生成系统 token,更新 sessionId 状态] C --> J[PC端轮询 /api/wechat/qr/status?sessionId=xxx] J -->|status=success| K[PC端保存 token,登录成功]

五、总结

  • 二维码 & sessionId:每次生成唯一二维码,绑定登录会话
  • 授权页面:微信官方提供,前端无需处理
  • PC 端轮询或 WebSocket:获取授权结果
  • 后端处理:用 code 换 token,生成系统 token,更新 session 状态

这种方式可以安全、方便地实现PC 端扫码登录,用户体验与微信官方一致。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/23 11:38:57

AI微信助手终极指南:如何实现智能对话新体验

AI微信助手终极指南&#xff1a;如何实现智能对话新体验 【免费下载链接】WeChatBot_WXAUTO_SE 将deepseek接入微信实现自动聊天的聊天机器人。本项目通过wxauto实现收发微信消息。原项目仓库&#xff1a;https://github.com/umaru-233/My-Dream-Moments 本项目由iwyxdxl在原项…

作者头像 李华
网站建设 2026/2/21 12:18:47

Sigma文件管理器:重塑数字文件管理的现代化解决方案

在数字信息爆炸的时代&#xff0c;高效的文件管理已成为每个人日常工作和生活中不可或缺的技能。传统文件管理器功能单一、界面陈旧&#xff0c;无法满足现代用户对智能化、个性化管理的需求。Sigma文件管理器作为一款免费开源的跨平台工具&#xff0c;通过创新的设计理念和强大…

作者头像 李华
网站建设 2026/2/22 1:39:27

如何用Estedad字体解决多语言排版难题:从混乱到专业

如何用Estedad字体解决多语言排版难题&#xff1a;从混乱到专业 【免费下载链接】Estedad Sans Serif Arabic-Latin text typeface 项目地址: https://gitcode.com/gh_mirrors/es/Estedad 你是否曾经遇到过这样的困扰&#xff1a;在同一个页面上显示阿拉伯语和拉丁语时&…

作者头像 李华
网站建设 2026/2/22 16:18:00

eDEX-UI跨平台终端模拟器:统一科幻界面的多系统完美体验

eDEX-UI跨平台终端模拟器&#xff1a;统一科幻界面的多系统完美体验 【免费下载链接】edex-ui GitSquared/edex-ui: edex-ui (eXtended Development EXperience User Interface) 是一个模拟未来科技感终端界面的应用程序&#xff0c;采用了React.js开发&#xff0c;虽然不提供实…

作者头像 李华
网站建设 2026/2/22 15:20:00

Redmi AX3000路由器性能升级全攻略:3步解锁OpenWrt隐藏技能

Redmi AX3000路由器性能升级全攻略&#xff1a;3步解锁OpenWrt隐藏技能 【免费下载链接】openwrt-redmi-ax3000 Openwrt for Redmi AX3000 / Xiaomi CR8806 / Xiaomi CR8808 / Xiaomi CR8809 项目地址: https://gitcode.com/gh_mirrors/op/openwrt-redmi-ax3000 还在为家…

作者头像 李华
网站建设 2026/2/23 10:33:36

函数的变量是地址与函数变量是数值的区别

在 C/C 里&#xff0c;“变量是地址”和“变量是数值”的区别&#xff0c;本质上是&#xff1a;这个变量里保存的比特位被解释成“数据本身”还是被解释成“指向某个内存位置/代码位置的地址”。二者在语义、可做的运算、以及对程序行为的影响上差别很大。 下面用最常见的场景…

作者头像 李华