UniApp + UniCloud 实现微信小程序静默登录
目录
1. 项目准备
1.1 环境要求
- HBuilderX 3.0+
- 微信开发者工具
- UniCloud 已开通
- 微信小程序已注册
1.2 项目配置
- 在 manifest.json 中配置微信小程序 AppID:
{
"mp-weixin": {
"appid": "你的小程序AppID",
"setting": {
"urlCheck": false
}
}
}
- 在 pages.json 中添加登录页面:
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
}
]
}
2. UniCloud 配置
2.1 数据库集合创建
- 创建用户集合
uni-id-users
:
{
"bsonType": "object",
"required": ["_id"],
"properties": {
"_id": {
"description": "ID,系统自动生成",
"bsonType": "string"
},
"wx_openid": {
"bsonType": "string",
"description": "微信openid"
},
"wx_unionid": {
"bsonType": "string",
"description": "微信unionid"
},
"session_key": {
"bsonType": "string",
"description": "微信会话密钥"
}
}
}
2.2 uni-config-center 配置
在 uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json
中配置:
{
"mp-weixin": {
"appid": "你的小程序AppID",
"appsecret": "你的小程序AppSecret"
}
}
3. 前端实现
3.1 登录工具类
创建 utils/login.js
:
export default class LoginManager {
static async silentLogin() {
try {
// 获取微信登录凭证
const { code } = await uni.login({
provider: 'weixin'
});
// 调用云函数登录
const { result } = await uniCloud.callFunction({
name: 'wx-silent-login',
data: { code }
});
// 保存登录状态
if (result.token) {
uni.setStorageSync('uni_id_token', result.token);
uni.setStorageSync('uni_id_token_expired', result.tokenExpired);
}
return result;
} catch (e) {
console.error('静默登录失败:', e);
throw e;
}
}
static async checkLoginState() {
const token = uni.getStorageSync('uni_id_token');
const tokenExpired = uni.getStorageSync('uni_id_token_expired');
if (!token || !tokenExpired || tokenExpired < Date.now()) {
return await this.silentLogin();
}
return { token, tokenExpired };
}
}
3.2 页面使用
在 pages/index/index.vue
中:
<template>
<view class="content">
<text>{{userInfo ? '已登录' : '未登录'}}</text>
</view>
</template>
<script>
import LoginManager from '@/utils/login.js'
export default {
data() {
return {
userInfo: null
}
},
onLoad() {
this.checkLogin()
},
methods: {
async checkLogin() {
try {
const loginState = await LoginManager.checkLoginState()
if (loginState.userInfo) {
this.userInfo = loginState.userInfo
}
} catch (e) {
console.error(e)
}
}
}
}
</script>
4. 云函数实现
4.1 创建云函数
创建 uniCloud/cloudfunctions/wx-silent-login/index.js
:
'use strict';
const uniID = require('uni-id-common')
exports.main = async function(event, context) {
const { code } = event
const uniIDIns = uniID.createInstance({ context })
try {
// 微信登录
const wxLoginRes = await uniIDIns.loginByWeixin({
code
})
// 如果是新用户,可以在这里进行额外处理
if (wxLoginRes.type === 'register') {
// 可以在这里添加用户初始化逻辑
}
return {
errCode: 0,
token: wxLoginRes.token,
tokenExpired: wxLoginRes.tokenExpired,
userInfo: wxLoginRes.userInfo
}
} catch (e) {
return {
errCode: e.errCode || -1,
errMsg: e.errMsg || '登录失败'
}
}
}
5. 完整示例
5.1 登录流程
- 应用启动时检查登录状态
- 如果未登录或登录过期,进行静默登录
- 获取 code 并调用云函数
- 云函数处理登录逻辑并返回结果
- 前端保存登录状态
5.2 示例代码
在 App.vue
中:
<script>
import LoginManager from '@/utils/login.js'
export default {
onLaunch: async function() {
try {
await LoginManager.checkLoginState()
} catch (e) {
console.error('登录失败:', e)
}
}
}
</script>
5.3 登录拦截器
创建 utils/request.js
:
const httpInterceptor = {
invoke(options) {
// 添加token
const token = uni.getStorageSync('uni_id_token')
if (token) {
options.header = {
...options.header,
'x-token': token
}
}
// 请求拦截
return options
},
success(response) {
// 如果token过期,尝试重新登录
if (response.data.errCode === 'TOKEN_INVALID') {
LoginManager.silentLogin()
}
return response
}
}
uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)
注意事项
- 确保微信小程序的 AppID 和 AppSecret 配置正确
- 处理好登录失败的情况
- 注意 token 的有效期管理
- 考虑数据安全性,避免敏感信息泄露
- 建议添加请求重试机制