278 lines
5.6 KiB
Markdown
278 lines
5.6 KiB
Markdown
# 微信小程序接入指南
|
||
|
||
## 后端API接口
|
||
|
||
### 1. 微信小程序登录
|
||
|
||
**接口地址**: `POST /api/auth/wechat/login`
|
||
|
||
**请求体**:
|
||
```json
|
||
{
|
||
"wechatLogin": {
|
||
"code": "微信小程序wx.login()获取的code"
|
||
},
|
||
"userInfo": {
|
||
"nickName": "用户昵称",
|
||
"avatarUrl": "用户头像URL"
|
||
}
|
||
}
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"user": {
|
||
"id": 1,
|
||
"username": "wx_12345678",
|
||
"email": "openid@wechat.local",
|
||
"realName": "用户昵称",
|
||
"avatar": "用户头像URL",
|
||
"role": "customer",
|
||
"status": "active"
|
||
},
|
||
"access_token": "JWT访问令牌",
|
||
"refresh_token": "JWT刷新令牌"
|
||
}
|
||
```
|
||
|
||
## 前端集成示例(uni-app)
|
||
|
||
### 1. 登录页面代码示例
|
||
|
||
```vue
|
||
<template>
|
||
<view class="login-container">
|
||
<button @click="wxLogin" class="wx-login-btn">微信登录</button>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
methods: {
|
||
// 微信登录
|
||
async wxLogin() {
|
||
try {
|
||
// 1. 获取微信登录code
|
||
const loginRes = await uni.login({
|
||
provider: 'weixin'
|
||
});
|
||
|
||
if (loginRes[1].code) {
|
||
// 2. 获取用户信息(可选)
|
||
const userInfo = await this.getUserInfo();
|
||
|
||
// 3. 发送到后端登录
|
||
const response = await uni.request({
|
||
url: 'http://localhost:3000/api/auth/wechat/login',
|
||
method: 'POST',
|
||
data: {
|
||
wechatLogin: {
|
||
code: loginRes[1].code
|
||
},
|
||
userInfo: userInfo
|
||
}
|
||
});
|
||
|
||
if (response[1].statusCode === 200) {
|
||
const { user, access_token, refresh_token } = response[1].data;
|
||
|
||
// 4. 保存用户信息和token
|
||
uni.setStorageSync('access_token', access_token);
|
||
uni.setStorageSync('refresh_token', refresh_token);
|
||
uni.setStorageSync('userInfo', user);
|
||
|
||
// 5. 跳转到首页
|
||
uni.switchTab({
|
||
url: '/pages/index/index'
|
||
});
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('登录失败:', error);
|
||
uni.showToast({
|
||
title: '登录失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
},
|
||
|
||
// 获取用户信息(可选)
|
||
async getUserInfo() {
|
||
try {
|
||
const userProfile = await uni.getUserProfile({
|
||
desc: '用于完善用户资料'
|
||
});
|
||
|
||
return {
|
||
nickName: userProfile[1].userInfo.nickName,
|
||
avatarUrl: userProfile[1].userInfo.avatarUrl
|
||
};
|
||
} catch (error) {
|
||
console.log('用户拒绝授权用户信息');
|
||
return null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.login-container {
|
||
padding: 40px;
|
||
text-align: center;
|
||
}
|
||
|
||
.wx-login-btn {
|
||
background-color: #07c160;
|
||
color: white;
|
||
border: none;
|
||
padding: 12px 24px;
|
||
border-radius: 4px;
|
||
font-size: 16px;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
### 2. API请求拦截器
|
||
|
||
```javascript
|
||
// utils/request.js
|
||
const BASE_URL = 'http://localhost:3000/api';
|
||
|
||
// 请求拦截器
|
||
uni.addInterceptor('request', {
|
||
invoke(args) {
|
||
// 添加基础URL
|
||
if (!args.url.startsWith('http')) {
|
||
args.url = BASE_URL + args.url;
|
||
}
|
||
|
||
// 添加认证头
|
||
const token = uni.getStorageSync('access_token');
|
||
if (token) {
|
||
args.header = {
|
||
...args.header,
|
||
'Authorization': `Bearer ${token}`
|
||
};
|
||
}
|
||
|
||
return args;
|
||
},
|
||
|
||
success(result) {
|
||
// 处理认证失败
|
||
if (result.statusCode === 401) {
|
||
// Token过期,尝试刷新或跳转登录
|
||
uni.removeStorageSync('access_token');
|
||
uni.removeStorageSync('userInfo');
|
||
uni.reLaunch({
|
||
url: '/pages/login/login'
|
||
});
|
||
}
|
||
|
||
return result;
|
||
}
|
||
});
|
||
|
||
export default {
|
||
// 封装请求方法
|
||
request(options) {
|
||
return uni.request({
|
||
...options,
|
||
header: {
|
||
'Content-Type': 'application/json',
|
||
...options.header
|
||
}
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 用户信息获取
|
||
|
||
```javascript
|
||
// pages/profile/profile.vue
|
||
export default {
|
||
data() {
|
||
return {
|
||
userInfo: {}
|
||
};
|
||
},
|
||
|
||
onLoad() {
|
||
this.getUserProfile();
|
||
},
|
||
|
||
methods: {
|
||
async getUserProfile() {
|
||
try {
|
||
const response = await uni.request({
|
||
url: '/users/profile',
|
||
method: 'GET'
|
||
});
|
||
|
||
if (response[1].statusCode === 200) {
|
||
this.userInfo = response[1].data;
|
||
}
|
||
} catch (error) {
|
||
console.error('获取用户信息失败:', error);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 配置说明
|
||
|
||
### 1. 后端环境配置
|
||
|
||
在 `.env` 文件中配置微信小程序信息:
|
||
|
||
```env
|
||
# 微信小程序配置
|
||
WECHAT_APPID=你的小程序AppID
|
||
WECHAT_SECRET=你的小程序AppSecret
|
||
```
|
||
|
||
### 2. 微信小程序配置
|
||
|
||
在 `manifest.json` 中配置微信小程序:
|
||
|
||
```json
|
||
{
|
||
"mp-weixin": {
|
||
"appid": "你的小程序AppID",
|
||
"setting": {
|
||
"urlCheck": false
|
||
},
|
||
"requiredPrivateInfos": ["getUserProfile"]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 请求域名配置
|
||
|
||
在微信小程序后台配置服务器域名:
|
||
- 开发环境: `http://localhost:3000`
|
||
- 生产环境: `https://yourdomain.com`
|
||
|
||
## 注意事项
|
||
|
||
1. **获取微信AppID和AppSecret**:
|
||
- 登录微信小程序后台
|
||
- 在"开发" -> "开发管理" -> "开发设置"中获取
|
||
|
||
2. **用户信息授权**:
|
||
- `getUserProfile` 需要用户主动触发
|
||
- 建议在用户首次登录时请求
|
||
|
||
3. **Token管理**:
|
||
- 访问令牌有效期7天
|
||
- 刷新令牌有效期30天
|
||
- 建议在请求拦截器中处理token刷新
|
||
|
||
4. **安全考虑**:
|
||
- AppSecret不要泄露到前端
|
||
- 生产环境使用HTTPS
|
||
- 定期更换JWT密钥 |