欢迎到专业群( uni-app 官方技术交流群 1 ) 咨询,群中有相关专业的管理员和群友。
下面给出一份“飞度在线网络购物平台”多端登录的完整思路 + 可落地的 uni-app(前端)+ Node.js(express) + MySQL(后端)代码示例。
所有登录方式共用同一张用户表、同一套 cookie-session 机制,方便你直接合并到现有工程。
一、数据库设计(MySQL)
-- 用户主表
create table fd_user(
id bigint primary key auto_increment,
uuid char(36) unique, -- 全局唯一用户 id
phone char(11) unique, -- 手机号(可为空)
wx_openid varchar(64) unique, -- 微信 openid
ali_openid varchar(64) unique, -- 支付宝 openid
pwd_hash char(60), -- 密码(bcrypt 60 位)
nickname varchar(32),
avatar varchar(255),
create_time datetime default current_timestamp
);
-- 验证码表(仅演示用,生产可放 redis)
create table fd_sms_code(
phone char(11) primary key,
code char(6),
expire_at datetime
);
-- pc 扫码登录临时表
create table fd_qrcode(
scene char(32) primary key, -- 场景码
uid bigint, -- 已绑定的用户 id(扫码后回填)
create_at datetime default current_timestamp,
expire_at datetime
);
二、后端 Node.js(express) 核心代码
- 通用中间件
// app.js
const express = require('express');
const session = require('express-session');
const cors = require('cors');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cors({ origin: true, credentials: true }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(session({
secret: 'feidu2024',
resave: false,
saveUninitialized: false,
cookie: { httpOnly: true, maxAge: 1000 * 60 * 60 * 24 }
}));
// 路由
app.use('/api', require('./routes/login'));
app.listen(3000);
- 登录路由 routes/login.js
const router = require('express').Router();
const bcrypt = require('bcrypt');
const mysql = require('mysql2/promise');
const db = mysql.createPool({ host:'localhost', user:'root', password:'123456', database:'feidu' });
// 工具:下发 cookie
function setLoginCookie(req, res, uid) {
req.session.uid = uid;
res.cookie('uid', uid, { maxAge: 1000 * 60 * 60 * 24, httpOnly: false });
}
/* 1. 手机号 + 验证码登录 */
router.post('/login/sms', async (req, res) => {
const { phone, code } = req.body;
const [rows] = await db.query('select * from fd_sms_code where phone=? and code=? and expire_at>now()', [phone, code]);
if (!rows.length) return res.json({ code: 400, msg: '验证码错误/过期' });
await db.query('delete from fd_sms_code where phone=?', [phone]); // 用完即删
let [user] = await db.query('select id from fd_user where phone=?', [phone]);
if (!user.length) {
const uuid = require('uuid').v4();
const [r] = await db.query('insert into fd_user(uuid,phone) values(?,?)', [uuid, phone]);
user = [{ id: r.insertId }];
}
setLoginCookie(req, res, user[0].id);
res.json({ code: 0, msg: '登录成功' });
});
/* 2. 微信 / 支付宝 OAuth 登录 */
router.post('/login/oauth', async (req, res) => {
const { provider, code } = req.body; // provider = weixin | alipay
// 下面演示微信,支付宝同理
const axios = require('axios');
const appid = '你的微信appid', secret = '你的微信secret';
const { data } = await axios.get(`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appid}&secret=${secret}&code=${code}&grant_type=authorization_code`);
const openid = data.openid;
const [user] = await db.query(`select id from fd_user where wx_openid=?`, [openid]);
let uid;
if (user.length) {
uid = user[0].id;
} else {
const uuid = require('uuid').v4();
const [r] = await db.query('insert into fd_user(uuid,wx_openid) values(?,?)', [uuid, openid]);
uid = r.insertId;
}
setLoginCookie(req, res, uid);
res.json({ code: 0, msg: '登录成功' });
});
/* 3. PC 扫码登录 */
// 3.1 生成二维码
router.get('/qrcode/create', async (req, res) => {
const scene = require('crypto').randomBytes(16).toString('hex');
await db.query('insert into fd_qrcode(scene,expire_at) values(?,date_add(now(),interval 5 minute))', [scene]);
res.json({ code: 0, scene });
});
// 3.2 轮询接口
router.get('/qrcode/check/:scene', async (req, res) => {
const [rows] = await db.query('select uid from fd_qrcode where scene=? and expire_at>now()', [req.params.scene]);
if (!rows.length) return res.json({ code: 404, msg: '二维码过期' });
if (!rows[0].uid) return res.json({ code: 201, msg: '待扫描' });
setLoginCookie(req, res, rows[0].uid);
res.json({ code: 0, msg: '登录成功' });
});
// 3.3 手机端确认扫码
router.post('/qrcode/confirm', async (req, res) => {
const { scene } = req.body;
const uid = req.session.uid; // 手机端已登录
if (!uid) return res.json({ code: 401, msg: '手机端未登录' });
await db.query('update fd_qrcode set uid=? where scene=?', [uid, scene]);
res.json({ code: 0 });
});
/* 4. 绑定第三方账号(手机号已登录后) */
router.post('/bind', async (req, res) => {
const uid = req.session.uid;
if (!uid) return res.json({ code: 401 });
const { provider, openid } = req.body;
const field = provider === 'weixin' ? 'wx_openid' : 'ali_openid';
await db.query(`update fd_user set ${field}=? where id=?`, [openid, uid]);
res.json({ code: 0 });
});
module.exports = router;
三、uni-app 前端示例
- 公共请求封装 utils/request.js
const baseURL = 'http://localhost:3000/api';
export default function request(url, data = {}, method = 'POST') {
return new Promise((resolve, reject) => {
uni.request({
url: baseURL + url,
method,
data,
withCredentials: true, // 关键:让 cookie 随请求一起发送
success: (res) => resolve(res.data),
fail: reject
});
});
}
- 手机号验证码登录页 pages/login/sms.vue
<template>
<view>
<input v-model="phone" placeholder="手机号" />
<input v-model="code" placeholder="验证码" />
<button @tap="sendCode">发送验证码</button>
<button @tap="loginSms">登录</button>
</view>
</template>
<script>
import req from '@/utils/request';
export default {
data() { return { phone: '', code: '' } },
methods: {
async sendCode() {
// 这里只是演示,真实场景需调短信网关
await req('/sms/send', { phone: this.phone });
uni.showToast({ title: '已发送' });
},
async loginSms() {
await req('/login/sms', { phone: this.phone, code: this.code });
uni.switchTab({ url: '/pages/index/index' });
}
}
};
</script>
- 微信 / 支付宝登录 pages/login/oauth.vue
<template>
<view>
<button @tap="login('weixin')">微信登录</button>
<button @tap="login('alipay')">支付宝登录</button>
</view>
</template>
<script>
import req from '@/utils/request';
export default {
methods: {
login(provider) {
uni.login({
provider,
success: async (res) => {
await req('/login/oauth', { provider, code: res.code });
uni.switchTab({ url: '/pages/index/index' });
}
});
}
}
};
</script>
- PC 扫码登录(H5 端) pages/login/qrcode.vue
1 个回复
Ask小助手 - Ask社区AI助手
下面给出一份“飞度在线网络购物平台”多端登录的完整思路 + 可落地的 uni-app(前端)+ Node.js(express) + MySQL(后端)代码示例。
所有登录方式共用同一张用户表、同一套 cookie-session 机制,方便你直接合并到现有工程。
一、数据库设计(MySQL)
二、后端 Node.js(express) 核心代码
三、uni-app 前端示例
要回复问题请先登录或注册
公告
更多>相关问题