当前位置:首页 > 热点

VueMySQL实现登录注册案例

登录注册这玩意儿,实现说穿了就是登录前端发请求、后端查数据库、注册对了就放行、案例错了就拒绝。实现但真动手写,登录坑不少。注册我用 Vue3 + Express + MySQL 搭了一套,案例跑通了,实现把关键环节拆出来说说。登录

前端用 Vue3 的注册 <script setup> 写法,登录页就两个输入框加一个按钮。案例核心逻辑不在模板里,实现在 submit 函数中。登录用户点按钮,注册先做本地校验——手机号是不是 11 位、密码有没有到 6 位。这步别省,不然空数据直接打到后端,日志里全是垃圾请求。校验过了,用 axios.post 把 { phone, password } 扔给 /api/login。注意要设置 withCredentials 吗?如果后端用 session 存登录态,需要;用 JWT 就不需要。我选的 JWT,因为跨域调试时 session 的 cookie 老出问题。

后端用 Express 起服务,body-parser 解析 JSON。先写注册路由 /api/register。接收参数后,第一件事是查重——SELECT id FROM users WHERE phone = ?。这里必须用参数化查询,别拼字符串,不然一个 ' OR '1'='1 就能把表拖走。查重通过后,密码不能明文存。我用 bcrypt 哈希,saltRounds 设 10。哈希完再 INSERT INTO users (phone, password_hash) VALUES (?, ?)。注册成功返回 { code: 0, msg: 'ok' },前端据此跳转到登录页。

登录路由 /api/login 稍微绕一点。先按手机号查用户,查不到直接返回“手机号或密码错误”——别返回“用户不存在”,那等于告诉攻击者哪些手机号已注册。查到了,用 bcrypt.compare 比对密码。比对成功,生成 JWT:jwt.sign({ uid: user.id }, secret, { expiresIn: '7d' })。这个 token 返回给前端,前端存 localStorage,后续请求放在 Authorization 头里。

有个细节我踩了坑:MySQL 的 users 表建的时候,phone 字段设了 VARCHAR(20) 且加了 UNIQUE 索引。但第一次测试时忘了设 utf8mb4 字符集,结果手机号里混入特殊字符时插入失败。后来改成 utf8mb4_unicode_ci 才稳。另外,password_hash 字段用 CHAR(60) 刚好,bcrypt 哈希固定 60 字符,别用 TEXT,浪费空间。

前端拿到 token 后,在路由守卫里判断 localStorage.getItem('token') 是否存在。不存在就 next('/login')。但光这样不够——token 可能过期。我在 axios 响应拦截器里加了一层:如果后端返回 401,就清掉本地 token 并跳登录页。后端那边,写个中间件 authMiddleware,从 req.headers.authorization 里取 token,jwt.verify 失败就 res.status(401).json({ msg: 'token invalid' })。这个中间件挂在需要登录的路由上,比如 /api/userinfo。

注册和登录的接口测试我用 Postman 跑了十几遍。最常出现的错误是 CORS——前端 5173 端口,后端 3000 端口,浏览器直接拦。解决方式是在 Express 里加 cors 中间件,app.use(cors({ origin: 'http://localhost:5173', credentials: true }))。如果前端带 cookie,credentials 必须为 true,同时后端 Access-Control-Allow-Origin 不能写 *,得写具体域名。

整套跑下来,代码量不大:前端两个组件、后端三个路由加一个中间件、一张用户表。但每个环节都有小坑,比如 bcrypt 的异步写法、JWT 的 secret 别硬编码在代码里(我放 .env 了)、MySQL 连接池要用 mysql2/promise 而不是回调版。写完这一套,再看到“登录注册”四个字,脑子里直接浮现出参数化查询和 401 拦截器,而不是什么高深架构。

分享到: