文章目录
uni-app微信小程序登录流程实战详解
作为前端开发者,理解微信小程序的登录流程对构建用户认证系统至关重要。本文将从前端开发角度,详细介绍如何在uni-app框架下实现微信小程序的登录流程,包括获取登录凭证、发送登录请求、管理登录状态等关键环节。
微信小程序登录流程概述
微信小程序的前端登录流程主要包括以下几个步骤:
- 调用 uni.login() 获取登录凭证(code)
- 将 code 发送到自己的业务服务器
- 接收服务器返回的登录态(token)
- 保存并管理登录态
- 在后续请求中使用登录态
接下来,我们将详细解析每个步骤的实现。
1. 获取登录凭证(code)
在小程序启动时,我们首先需要调用 uni.login()
方法获取登录凭证(code):
// 获取微信登录凭证
function getWxLoginCode() {
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success: (res) => {
if (res.code) {
console.log('登录凭证获取成功');
resolve(res.code);
} else {
console.error('登录凭证获取失败:', res.errMsg);
reject(new Error(res.errMsg));
}
},
fail: (err) => {
console.error('登录接口调用失败:', err);
reject(err);
}
});
});
}
这段代码封装了 uni.login()
方法,返回一个 Promise 对象,便于我们使用 async/await 语法处理异步流程。
2. 发送登录请求
获取到 code 后,我们需要将其发送到自己的业务服务器,以换取自定义登录态:
// 发送登录请求
async function login() {
try {
// 显示加载提示
uni.showLoading({
title: '登录中...'
});
// 获取微信登录凭证
const code = await getWxLoginCode();
// 发送登录请求
const result = await request({
url: '/api/user/login',
method: 'POST',
data: { code }
});
// 处理登录结果
if (result.code === 0 && result.data) {
// 登录成功,保存登录态
saveLoginState(result.data);
return result.data;
} else {
// 登录失败
uni.showToast({
title: result.msg || '登录失败',
icon: 'none'
});
return null;
}
} catch (error) {
// 处理错误
console.error('登录过程发生错误:', error);
uni.showToast({
title: '登录失败,请重试',
icon: 'none'
});
return null;
} finally {
// 隐藏加载提示
uni.hideLoading();
}
}
这段代码完成了以下工作:
- 调用
getWxLoginCode()
获取登录凭证 - 将 code 发送到业务服务器
- 处理服务器返回的登录结果
- 提供用户友好的反馈(加载提示、错误提示)
3. 保存登录态
当服务器返回登录态(通常是 token)后,我们需要将其保存起来:
// 保存登录状态
function saveLoginState(loginData) {
// 保存 token 到本地存储
uni.setStorageSync('token', loginData.token);
// 保存用户信息
if (loginData.userInfo) {
uni.setStorageSync('userInfo', loginData.userInfo);
}
// 记录登录时间
uni.setStorageSync('loginTime', Date.now());
console.log('登录状态已保存');
}
在这里,我们使用 uni-app 提供的存储 API 保存了 token、用户信息和登录时间。这些信息将在后续的请求和页面中使用。
4. 登录状态管理
为了有效管理登录状态,我们需要提供一套完整的工具函数:
// 检查是否已登录
function isLoggedIn() {
return !!uni.getStorageSync('token');
}
// 获取当前token
function getToken() {
return uni.getStorageSync('token') || '';
}
// 获取用户信息
function getUserInfo() {
return uni.getStorageSync('userInfo') || null;
}
// 清除登录状态
function clearLoginState() {
uni.removeStorageSync('token');
uni.removeStorageSync('userInfo');
uni.removeStorageSync('loginTime');
}
// 检查登录是否过期
function isLoginExpired() {
const loginTime = uni.getStorageSync('loginTime') || 0;
const currentTime = Date.now();
// 假设登录有效期为7天
const expiresIn = 7 * 24 * 60 * 60 * 1000;
return currentTime - loginTime > expiresIn;
}
// 刷新登录状态
async function refreshLogin() {
if (isLoginExpired()) {
clearLoginState();
return await login();
}
return true;
}
这组函数提供了:
- 检查用户是否已登录
- 获取 token 和用户信息
- 清除登录状态
- 检查登录是否过期
- 刷新登录状态
5. 应用登录状态
有了上述工具函数,我们需要在应用中合理使用它们:
请求拦截器中添加 token
// 请求拦截器
const request = (options) => {
// 克隆原始选项
const requestOptions = {
...options,
header: options.header || {}
};
// 添加 token 到请求头
const token = getToken();
if (token) {
requestOptions.header.Authorization = `Bearer ${token}`;
}
// 发送请求
return new Promise((resolve, reject) => {
uni.request({
...requestOptions,
success: (res) => {
// 检查响应状态
if (res.statusCode === 200) {
resolve(res.data);
} else if (res.statusCode === 401) {
// token 无效或过期
handleUnauthorized();
reject(new Error('未授权'));
} else {
reject(res);
}
},
fail: (err) => {
reject(err);
}
});
});
};
// 处理未授权情况
function handleUnauthorized() {
// 清除登录状态
clearLoginState();
// 提示用户
uni.showToast({
title: '登录已过期,请重新登录',
icon: 'none'
});
// 跳转到登录页
setTimeout(() => {
uni.navigateTo({
url: '/pages/login/login'
});
}, 1500);
}
这个请求拦截器确保了:
- 每个请求都带上 token
- 处理 401 未授权响应
- 在 token 无效时引导用户重新登录
自动登录
在应用启动时,我们可以实现自动登录功能:
// App.vue 的 onLaunch 钩子
export default {
async onLaunch() {
// 检查本地是否有登录态
if (isLoggedIn()) {
// 检查登录是否过期
if (isLoginExpired()) {
console.log('登录已过期,尝试重新登录');
await login();
} else {
console.log('已登录状态');
}
} else {
console.log('未登录状态');
await login();
}
}
}
这段代码在应用启动时检查登录状态,并在必要时进行自动登录。
页面路由守卫
在需要登录才能访问的页面,我们可以添加路由守卫:
// 需要登录的页面
export default {
onLoad() {
this.checkLogin();
},
methods: {
checkLogin() {
if (!isLoggedIn()) {
uni.showToast({
title: '请先登录',
icon: 'none'
});
// 跳转到登录页
setTimeout(() => {
uni.navigateTo({
url: '/pages/login/login'
});
}, 1500);
return false;
}
return true;
}
}
}
使用 Vuex 集中管理登录状态
为了更好地管理状态,我们可以使用 Vuex:
// store/modules/user.js
const state = {
token: uni.getStorageSync('token') || '',
userInfo: uni.getStorageSync('userInfo') || null
};
const mutations = {
SET_TOKEN(state, token) {
state.token = token;
uni.setStorageSync('token', token);
},
SET_USER_INFO(state, userInfo) {
state.userInfo = userInfo;
uni.setStorageSync('userInfo', userInfo);
},
CLEAR_USER(state) {
state.token = '';
state.userInfo = null;
uni.removeStorageSync('token');
uni.removeStorageSync('userInfo');
uni.removeStorageSync('loginTime');
}
};
const actions = {
// 登录
async login({ commit }) {
try {
uni.showLoading({ title: '登录中...' });
// 获取微信登录凭证
const code = await getWxLoginCode();
// 发送登录请求
const result = await request({
url: '/api/user/login',
method: 'POST',
data: { code }
});
if (result.code === 0 && result.data) {
// 保存登录状态
commit('SET_TOKEN', result.data.token);
commit('SET_USER_INFO', result.data.userInfo);
uni.setStorageSync('loginTime', Date.now());
return result.data;
} else {
uni.showToast({
title: result.msg || '登录失败',
icon: 'none'
});
return null;
}
} catch (error) {
console.error('登录失败', error);
uni.showToast({
title: '登录失败,请重试',
icon: 'none'
});
return null;
} finally {
uni.hideLoading();
}
},
// 登出
logout({ commit }) {
commit('CLEAR_USER');
uni.reLaunch({
url: '/pages/login/login'
});
},
// 检查登录状态
checkLogin({ state, dispatch }) {
if (!state.token) {
return false;
}
const loginTime = uni.getStorageSync('loginTime') || 0;
const currentTime = Date.now();
const expiresIn = 7 * 24 * 60 * 60 * 1000;
if (currentTime - loginTime > expiresIn) {
// 登录过期,重新登录
return dispatch('login');
}
return true;
}
};
export default {
namespaced: true,
state,
mutations,
actions
};
使用 Vuex 管理登录状态有以下优势:
- 集中管理状态
- 状态变化更加可预测
- 方便组件之间共享状态
- 提供统一的 API 接口
登录组件示例
最后,我们来看一个完整的登录组件示例:
<!-- pages/login/login.vue -->
<template>
<view class="login-container">
<image class="logo" src="/static/logo.png"></image>
<view class="welcome">欢迎使用向明天小程序</view>
<button
class="login-btn"
type="primary"
:loading="loading"
@click="handleLogin"
>
微信一键登录
</button>
<view class="tips">登录后即可使用完整功能</view>
</view>
</template>
<script>
import { mapActions } from 'vuex';
export default {
data() {
return {
loading: false
};
},
methods: {
...mapActions('user', ['login']),
async handleLogin() {
this.loading = true;
try {
const result = await this.login();
if (result) {
uni.showToast({
title: '登录成功',
icon: 'success'
});
// 登录成功后跳转
setTimeout(() => {
const redirectUrl = uni.getStorageSync('redirectUrl') || '/pages/index/index';
uni.reLaunch({
url: redirectUrl
});
uni.removeStorageSync('redirectUrl');
}, 1500);
}
} catch (error) {
console.error('登录操作失败', error);
} finally {
this.loading = false;
}
}
}
};
</script>
<style>
.login-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60rpx;
height: 100vh;
background-color: #f8f8f8;
}
.logo {
width: 200rpx;
height: 200rpx;
margin-bottom: 40rpx;
}
.welcome {
font-size: 36rpx;
font-weight: bold;
margin-bottom: 80rpx;
color: #333;
}
.login-btn {
width: 80%;
height: 88rpx;
line-height: 88rpx;
border-radius: 44rpx;
font-size: 32rpx;
background-color: #07c160;
}
.tips {
margin-top: 40rpx;
font-size: 28rpx;
color: #999;
}
</style>
登录流程最佳实践
静默登录:在用户无感知的情况下完成登录流程,提升用户体验。
登录状态检查:在应用启动和页面切换时检查登录状态,确保用户处于登录状态。
错误处理:提供友好的错误提示,引导用户成功完成登录。
登录重试:在登录失败时提供重试机制。
登录过期处理:及时处理登录过期情况,引导用户重新登录。
登录态持久化:使用适当的存储方式保存登录态,确保用户下次打开应用时能够保持登录状态。
登录态安全:不在前端存储敏感信息,设置合理的 token 过期时间。
总结
作为前端开发者,实现微信小程序登录流程需要关注以下关键点:
- 正确调用
uni.login()
获取登录凭证 - 将登录凭证发送到业务服务器换取登录态
- 安全地保存和管理登录态
- 在网络请求中使用登录态
- 处理登录过期和未授权情况
- 优化用户登录体验
通过本文介绍的方法和最佳实践,你应该能够在 uni-app 项目中实现一个完整、安全、用户友好的微信小程序登录流程。
希望这篇文章对你实现微信小程序登录功能有所帮助!