news 2026/7/18 13:37:41

阶段四:模拟微信 OAuth 登录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
阶段四:模拟微信 OAuth 登录

从零构建带AI流式对话的Vue2全栈应用-CSDN博客本文是对这篇文章阶段四的讲解

一、为什么不能只用一个“登录成功”按钮

真正的第三方登录不是前端自己决定登录成功。

需要经过:

你的前端 微信授权服务器 你的后端

基本流程:

用户点击微信登录 ↓ 跳转微信授权页 ↓ 微信返回临时 code ↓ 前端把 code 交给后端 ↓ 后端验证 code ↓ 后端建立自己系统的登录状态

阶段四没有真实微信资质,所以使用本地页面模拟微信。


二、OAuth 中的几个重要概念

1.code

code是一次性临时授权码。

它不是最终登录 Token。

特点:

有效时间短 通常只能使用一次 由微信授权后返回 应该交给后端验证

2.state

state是前端登录前生成的随机字符串。

登录前保存:

sessionStorage.setItem( 'wechat_oauth_state', state )

回调时比较:

returnedState === expectedState

它的作用类似取号票。

登录前:前端取一张号码票 登录回来:检查是不是同一张票

如果不一致,说明这个回调可能不是当前登录操作产生的。


3. Token

后端验证code后,生成自己的 Token。

Token 表示:

这个浏览器已经登录为哪个用户。

阶段四中 Token 放在 Vuex 内存中。


三、后端为什么使用Map

const authorizationCodes = new Map() const loginTokens = new Map()

Map是 JavaScript 的键值集合。

可以理解成字典。

保存授权码:

authorizationCodes.set(code, { user: mockWechatUser, expiresAt: ... })

读取授权码:

authorizationCodes.get(code)

删除授权码:

authorizationCodes.delete(code)

登录 Token 也是一样:

Token → 当前用户

四、生成随机字符串

function createRandomString(byteLength = 24) { return crypto .randomBytes(byteLength) .toString('hex') }

crypto.randomBytes()用于生成安全随机数据。

不能简单地使用:

Math.random()

生成真正的登录 Token,因为安全性不够。

生成结果类似:

83a6ce8f019d7d8d...

五、获取授权地址接口

前端请求:

GET /api/auth/wechat/authorize-url

携带:

redirectUri state

后端返回:

{ authorizeUrl: 'http://localhost:3000/mock-wechat/authorize?...' }

前端执行:

window.location.href = result.authorizeUrl

这不是 Vue 路由跳转,而是整个浏览器跳转到新的网页地址。


六、模拟微信授权页面

后端使用:

res.type('html').send(` <!DOCTYPE html> <html> ... </html> `)

返回一整个 HTML 页面。

浏览器访问:

http://localhost:3000/mock-wechat/authorize

时,不显示 JSON,而是显示绿色授权页面。

点击同意后,访问:

/mock-wechat/approve

后端生成code,再重定向回前端。


七、重定向回 Hash 路由

前端使用的是 Hash 路由:

http://localhost:8081/#/oauth/callback

需要把参数放在#后面的路由中:

http://localhost:8081/#/oauth/callback?code=xxx&state=xxx

前端才能通过:

this.$route.query.code this.$route.query.state

读取。


八、一次性授权码

后端生成:

authorizationCodes.set(code, { user: mockWechatUser, expiresAt: Date.now() + 5 * 60 * 1000 })

五分钟有效。

换取登录状态时:

authorizationCodes.delete(code)

先删除,再使用。

这表示同一个code第二次使用会失败。


九、阶段四鉴权中间件

function requireAuth(req, res, next) { const authorization = req.headers.authorization || '' if ( !authorization.startsWith( 'Bearer ' ) ) { return res.status(401).json({ code: 401, message: '请先登录' }) } const token = authorization.slice( 'Bearer '.length ) const currentUser = loginTokens.get(token) if (!currentUser) { return res.status(401).json({ code: 401, message: '登录状态无效' }) } req.currentUser = currentUser req.currentToken = token next() }

next()是什么

Express 中间件处理完以后,需要调用:

next()

才能继续执行真正的接口。

流程:

请求 /api/users ↓ 先执行 requireAuth ↓ Token 无效:直接返回 401 Token 有效:执行 next() ↓ 继续执行用户接口

Bearer Token 格式

前端请求头:

Authorization: Bearer abc123

后端先检查:

startsWith('Bearer ')

再去掉前面的文字:

authorization.slice('Bearer '.length)

最终得到:

abc123

十、阶段四 Vuex

state: { authToken: null, currentUser: null }

登录前:

authToken = null currentUser = null

登录后:

this.$store.commit( 'setAuth', result )

触发 mutation:

setAuth(state, payload) { state.authToken = payload.token state.currentUser = payload.user }

为什么 mutation 不能随便省略

推荐的数据修改流程:

组件 ↓ commit mutation ↓ 修改 state

而不是在组件中到处写:

this.$store.state.authToken = token

使用 mutation 能让数据变化更清楚,也方便调试。


十一、Axios 自动添加 Token

请求拦截器:

const token = store.state.authToken if (token) { config.headers.Authorization = `Bearer ${token}` }

登录后每次发送 Axios 请求都会自动带上:

Authorization: Bearer ...

所以页面调用:

getUsers()

时,不需要自己再写 Token。


十二、路由守卫

router.beforeEach((to, from, next) => { const requiresAuth = to.matched.some(record => { return record.meta.requiresAuth }) const isLoggedIn = store.getters.isLoggedIn if ( requiresAuth && !isLoggedIn ) { next('/login') return } next() })

to

将要进入的页面。

from

当前离开的页面。

next

决定下一步去哪里。

next()

正常进入目标页面。

next('/login')

改为进入登录页。


to.matched.some

一个页面可能匹配父路由和子路由。

to.matched.some(...)

检查所有匹配的路由中,有没有:

meta.requiresAuth === true

有就说明页面需要登录。


十三、阶段四为什么刷新后会退出

阶段四 Token 只保存在 Vuex:

authToken: null

Vuex 是网页内存。

按 F5 后:

页面重新加载 Vue 应用重新创建 Vuex 重新创建 authToken 恢复 null 路由守卫判断未登录 跳转登录页

这不是错误,而是阶段四设计上的限制。

阶段五会解决这个问题。

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

5分钟掌握Diablo Edit2:暗黑破坏神II终极角色编辑器完全指南

5分钟掌握Diablo Edit2&#xff1a;暗黑破坏神II终极角色编辑器完全指南 【免费下载链接】diablo_edit Diablo II Character editor. 项目地址: https://gitcode.com/gh_mirrors/di/diablo_edit 你是否厌倦了在暗黑破坏神II中反复刷怪只为获得一件完美装备&#xff1f;是…

作者头像 李华
网站建设 2026/7/18 13:33:38

2026车载软件全栈进阶路线 | 五阶段分层夯实基础、量产项目落地实战、MISRA/CAN/AUTOSAR全代码赋能求职进阶

目录 一、前言:2026车载软件行业人才标准与学习痛点 二、三类人群适配学习周期与岗位对标 2.1 零基础在校应届生(6-8个月全栈通关) 2.2 传统嵌入式转行者(4-6个月快速转型) 2.3 在职初级工程师进阶(2-3年深耕高薪赛道) 三、五阶段分层递进全栈学习体系(2026最新完…

作者头像 李华
网站建设 2026/7/18 13:32:03

AI应用安全攻防实战:从攻击链框架到纵深防御体系构建

1. 项目概述&#xff1a;当AI成为攻击者的新武器 最近几年&#xff0c;AI技术&#xff0c;尤其是大语言模型&#xff0c;已经从一个纯粹的辅助工具&#xff0c;演变成了一个复杂的、多层次的攻击面。我们过去谈应用安全&#xff0c;关注的是代码漏洞、配置错误、权限滥用。但现…

作者头像 李华
网站建设 2026/7/18 13:31:20

GPT5.6驱动AI拆书仿写:从原著分析到百万字网文大纲生成

如果你曾经尝试过写小说&#xff0c;特别是网文&#xff0c;一定体会过那种面对空白文档的恐惧&#xff1a;人物设定、情节推进、世界观构建……每一个环节都可能让创作卡壳。更不用说动辄百万字的大纲规划&#xff0c;光是想到要填满这么多内容就让人望而却步。 但最近AI写作…

作者头像 李华
网站建设 2026/7/18 13:31:08

49.C语言本地文件读写实战:从基础到嵌入式应用

一、文件操作的核心逻辑文件操作的本质是实现“内存临时数据”与“磁盘持久化数据”的交互&#xff0c;核心流程可概括为三步&#xff1a;打开文件&#xff1a;通过fopen建立程序与文件的连接&#xff0c;指定读写模式&#xff1b;读写数据&#xff1a;使用fprintf/fscanf等函数…

作者头像 李华