uni-id 怎么用于H5 uni-app

本文介绍了如何将uni-id插件应用于H5 uni-app,详细讲解了注册、主页、登录页面的实现过程,包括云函数的使用、token检测、登录注册逻辑等,并提供了相关页面设置和请求模板的总结。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过分析uni-id 插件,将可用的部分用于自己写的H5页面。

文末有总结 测试用网站的地址

uni-id 官方文档地址

一、注册页面 reg.vue

  • 注册页面的路径 pages/reg/reg.vue
1.1 点击注册按钮后触发register函数
  • 注册请求发送到了 user-center 云函数
  • 我们可以理解 user-center 是一个路由云函数
  • action: ‘register’ 是向服务器说明了是 注册行为
  • 注册成功了,就本地保存 “用户名” 和 “token”
  • 页面跳转至 主页 main.vue `
methods: {
	register() {
		const data = {
			username: this.username,
			password: this.password
			};
		uniCloud.callFunction({
			name: 'user-center',
			data: {
				action: 'register',
				params: data
			},
		success(e) {
			if (e.result.code === 0) {
			uni.showToast({
				title: '注册成功'
			});
			uni.setStorageSync('uni_id_token', e.result.token)
			uni.setStorageSync('username', e.result.username)
			uni.reLaunch({
				url: '../main/main',
			});
		} else {
			uni.showModal({
				content: JSON.stringify(e.result),
				showCancel: false
			})
		  }
		},
		fail(e) {
			uni.showModal({
				content: JSON.stringify(e),
				showCancel: false
			})
	  	  }
	  })
    }
 }
1.2 云函数 user-center 接收注册信息并返回结果
  • uniID = require('uni-id')=>uniIDIns = uniID.createInstance({ })
  • uniIDIns.register(params)可以看出,请求又指向了uni-id
  • 无需理解 uni-id 如何处理数据,返回值 res.result 包含了全部所需
`我们不用去研究 uni-id 的代码,只需要知道
 res.result.code === 0 就表示注册成功了
 res.result 包含了我们需要的全部信息`
const uniID = require('uni-id')
const db = uniCloud.database()

exports.main = async (event, context) => {
   const uniIDIns = uniID.createInstance({
     context
   })
   let params = event.params || {}
   switch (event.action) {
		case 'register':
			res = await uniIDIns.register(params);
			break;
   }
}

二、主页 main.vue

  • 主页路径 pages/main/main.vue
2.1 onLoad页面初始化
  • 这里需要用到 vuex 的内容,公用函数 login 公用数据'forcedLogin', 'hasLogin', 'userName'
  • computed: mapState(['forcedLogin', 'hasLogin', 'userName'])
  • methods: { ...mapMutations(['login']) }
  • uni_id_token保存在 token 信息
  • 有本地token时,调用云函数user-center向服务器表明了checkToken 检测token行为
  • loginType === 'local'应该是APP用的,H5 页面 loginType 始终 === 'online'
  • 没有本地token时,调用this.guideToLogin(),要求必须登录,调用了工具类函数univerifyLogin(),是APP、小程序才能用的一体登录系统
  • 请求数据时并未看到传递参数,根据官方文档,参数已经自动传送了
  • 检测 token 的官方文档,截图如下:
    文档截图
onLoad() {
	const loginType = uni.getStorageSync('login_type')
    //loginType === 'local' `应该是APP用的,H5 页面 `loginType 始终 === 'online' 
	if (loginType === 'local') {
		this.login(uni.getStorageSync('username'))
		return
	}
	let uniIdToken = uni.getStorageSync('uni_id_token')
	if (uniIdToken) {
		this.login(uni.getStorageSync('username'))
        //调用云函数 user-center 向服务器表明了是检测 token 		
		uniCloud.callFunction({
			name: 'user-center',
			data: {
				action: 'checkToken',
			},
			success: (e) => {
				console.log('checkToken success', e);
				if (e.result.code > 0) {
				//token过期或token不合法,重新登录
				if (this.forcedLogin) {
					uni.reLaunch({
						url: '../login/login'
					});
				} else {
					uni.navigateTo({
						url: '../login/login'
					});
					}
			  	}
			},
			fail(e) {
				uni.showModal({
				 	content: JSON.stringify(e),
					showCancel: false
				})
			}
		})
	} else {
		this.guideToLogin()
	}
}
2.2 user-center处理 checkToken
  • 无需关注代码处理逻辑,只需知道结果里有 payload表明检测失败
  • 成功或者失败,都会跳转到 登录页面
  • res.result 返回的结果,如图:
    在这里插入图片描述
//表示检测失败
payload = await uniIDIns.checkToken(event.uniIdToken)
	if (payload.code && payload.code > 0) {
		return payload
	}
//表示检测成功
switch (event.action) {
	case 'checkToken':
		res = await uniIDIns.checkToken(event.uniIdToken);
		break;
}

三、登录页面 login.vue

  • 登录页路径 pages/login/login.vue
3.1 onLoad()初始化数据
  • this.captcha('createCaptcha') 向 user-center 请求 createCaptcha
  • case 'createCaptcha':res = await uniCaptcha.create(params)break;
  • const uniCaptcha = require('uni-captcha')可以看出请求转到了 uni-captcha图文验证码模块
  • 图文验证码模块 的运行逻辑
<template>
	/*neddCaptcha控制着图文验证码的显示
      neddCaptcha 来自于 uni-needCaptcha 是一个布尔值
	  uni-needCaptcha 来自于 login 请求获得的 
	  当登录验证成功时,就等于 false ; 当登录验证失败时,就等于 e.result.needCaptcha 也就是 true
	  当为 true 时,调用了 this.captcha('createCaptcha'),也就是获取图文码的网络地址,最终显示到img中
	*/
	<view v-if="needCaptcha" class="input-row">
		<text class="title">验证码:</text>
		<m-input type="text" v-model="captchaText" placeholder="请输入验证码"></m-input>
		<view class="send-code-btn captcha-view" @click="captcha('refreshCaptcha')">
			<i v-if="captchaing" class="uni-icon_toast uni-loading"></i>
			<img v-if="!captchaing" :src="captchaBase64" width="100%" height="100%"></img>
		</view>
	</view>
</template>
<script>
 import {mapState,mapMutations} from 'vuex'
 import {getDeviceUUID} from '@/common/utils.js'
 const captchaOptions = {deviceId: getDeviceUUID(),scene: 'login'}
data() {
	return {
		needCaptcha: uni.getStorageSync('uni-needCaptcha')
	}
},
onLoad() {
	if (this.needCaptcha) {
		this.captcha('createCaptcha')
	}
}

async captcha(action, args) {
	if (this.captchaing) return;

	// 验证不loading
	this.captchaing = true;

	let {result: res} = await uniCloud.callFunction({
			name: 'user-center',
			data: {
				action,
				params: {
					...captchaOptions,
					...args
				}
			}
		 })
	this.captchaing = false;
		if (res.code === 0) {
			this.captchaBase64 = res.captchaBase64
		} else {
			uni.showToast({
				icon: 'none',
				title: res.message,
				duration: 1000
			})
	}
	return res;
}
</script>
3.2 onReady()
  • this.initProvider() 调用了uni.getProvider()在H5页面无效,参考下方官方文档
  • uni.getProvider官网文档
  • this.initPosition();调取了 uni.getSystemInfoSync()防止页面CSS样式变形
onReady() {
	this.initPosition();
	this.initProvider();
	// #ifdef MP-WEIXIN
	this.isDevtools = uni.getSystemInfoSync().platform === 'devtools';
	// #endif
}
3.3 点击登录按钮触发的函数
  • bindLogin() 切换 短信验证码登录 或者 密码登录
bindLogin() {
	switch (this.loginType) {
		case 0:
			this.loginBySms()
			break;
		case 1:
			this.loginByPwd()
			break;
		default:
			break;
	}
}
3.4 账号,密码登录
  • loginByPwd() 调用了云函数user-center标明了是login登录行为
async loginByPwd() {
	const data = {
		username: this.username,
		password: this.password,
		captcha: this.captchaText,
		...captchaOptions
	};
	this.loginBtnLoading = true
	uniCloud.callFunction({
		name: 'user-center',
		data: {
			action: 'login',
			params: data
		},
		success: (e) => {
			if (e.result.code == 0) {
				this.needCaptcha = false;
				uni.setStorageSync('uni-needCaptcha', this.needCaptcha)
				uni.setStorageSync('uni_id_token', e.result.token)
				uni.setStorageSync('username', e.result.username)
				uni.setStorageSync('login_type', 'online')
				uni.setStorageSync('uni_id_has_pwd', true)
				this.toMain(this.username);
			} else {
				uni.showModal({
					content: e.result.message,
					showCancel: false
				})

				this.needCaptcha = e.result.needCaptcha;
				uni.setStorageSync('uni-needCaptcha', this.needCaptcha)
				if (this.needCaptcha) {
					this.captcha('createCaptcha')
				}
			}
		},
		fail: (e) => {
			uni.showModal({
				content: JSON.stringify(e),
				showCancel: false
			})
		},
		complete: () => {
			this.loginBtnLoading = false
		}
	})
}

toMain(userName) {
	this.login(userName);
	/**
	* 强制登录时使用reLaunch方式跳转过来
	* 返回首页也使用reLaunch方式
	*/
	uni.reLaunch({
		url: '../main/main',
		});
}
3.5 user-center 登录请求
switch (event.action) {
	case 'login':
		let passed = false;
		let needCaptcha = await getNeedCaptcha();
		if (needCaptcha) {
			res = await uniCaptcha.verify(params)
			if (res.code === 0) passed = true;
			}
		if (!needCaptcha || passed) {
			res = await uniIDIns.login(params);
			await loginLog(res);
			needCaptcha = await getNeedCaptcha();
		}
		res.needCaptcha = needCaptcha;
		break;
}

四、总结

  • 将整套uni-id插件导入编辑器,上传所有云函数及公用函数。
  • pages页面全部删除,自建主页,登录页,注册页,修改密码页。
  • 保留全部VUEX部分
  • common 工具类函数保留 utils.js
4.1 主页设置
  • onLoad() 即开始检测 token
  • 本地 uni_id_token 保存着 token 信息,分为两种情况:有token和没有token
  • 本地 token 正确也未过期,修改VUEX状态this.login(uni.getStorageSync('username'));
  • 本地 token 错误或者过期了,跳转登录页面uni.reLaunch({url: '../login/login'});
  • 本地没有 token ,跳转至登录页面
  • 请求模板uniCloud.callFunction({name: 'user-center',data: {action: 'checkToken'})
import { mapState, mapMutations } from 'vuex';
export default {
	computed: mapState(['userName', 'hasLogin']),
	data() {
		return {
		};
	},
	onLoad() {
		let uid = { uid: `${uni.getStorageSync('user_id')}` };
		let uniIdToken = uni.getStorageSync('uni_id_token');
		if (uniIdToken) {
		//有 token 的情况下,开始检测
			uniCloud.callFunction({
				name: 'user-center',
				data: {
					action: 'checkToken'
				},
				success: e => {
					if (e.result.code > 0) {
				  //检测 token 有问题,返回登录页
						uni.reLaunch({
							url: '../login/login'
						});
					}
			this.login(uni.getStorageSync('username'));
				},
				fail(e) {
					uni.showModal({
						content: e.msg,
						showCancel: false
					});
				}
			});
		} else {
		//没有 token 的情况下,返回登录页
			uni.showModal({
				content: '请登录后再浏览',
				showCancel: false,
				success: res => {
					if (res.confirm) {
						uni.reLaunch({
							url: '../login/login'
						});
					}
				}
			});
		}
	},
	methods: {
		...mapMutations(['login']),
		login_out() {
			uni.reLaunch({
				url: '../login/login'
			});
		}
	}
};
4.2 登录页面设置
  • 登录后,保存了tokenusernameuser_id,然后跳转到主页
  • 登录密码错误后的图文验证码模块
  • user_id 将用于删除云数据库uni-id-log中过多的、重复的登录记录。 文末有删除记录的云函数方法。
  • 请求模板uniCloud.callFunction({name: 'user-center',data: {action: 'login',params: data})
  • 注意请求的参数格式{username:'',password:'',captcha:'',...captchaOptions}
import {mapState,mapMutations} from 'vuex';
import {getDeviceUUID} from '@/common/utils.js';
const captchaOptions = {deviceId: getDeviceUUID(),scene: 'login'};
export default {
	computed: mapState(['userName','forcedLogin']),
	data() {
		return {
			setHeight: '',
			isShow: false,
			dataIndex: '1',
			tipMsg: '提示:用户名,中英文均可',
			nameTrue: false,
			wordTrue: false,
			againTrue: false,
			nameVal: '',
			wordVal: '',
			againVal: '',
			needCaptcha: uni.getStorageSync('uni-needCaptcha'),
			captchaing: false,
			captchaBase64: '',
			captchaText: ''
		};
	},
	onLoad() {
		this.setHeight = `height:${uni.getSystemInfoSync().windowHeight}px;`;
		if(uni.getStorageSync('username')){
			this.nameVal = uni.getStorageSync('username');
		}else{
			uni.showModal({
				content:'请您先注册或者登录',
				showCancel: false
			});
		}
		if (this.needCaptcha) {
			this.captcha('createCaptcha')
		}
	},
	methods: {
		...mapMutations(['login']),
		loginByPwd() {
				const data = {
					username: this.nameVal,
					password: this.againVal,
					captcha: this.captchaText,
					...captchaOptions
				};
				uniCloud.callFunction({
					name: 'user-center',
					data: {
						action: 'login',
						params: data
					},
					success: (e) => {
						if (e.result.code == 0) {
							console.log('登陆成功');
							this.needCaptcha = false;
							uni.setStorageSync('uni-needCaptcha', this.needCaptcha);
							uni.setStorageSync('uni_id_token', e.result.token);
							uni.setStorageSync('username', e.result.username);
							uni.setStorageSync('user_id', e.result.uid);
							this.toMain(this.nameVal);
						} else {
							uni.showModal({
								content: e.result.message,
								showCancel: false
							})
						}
						this.needCaptcha = e.result.needCaptcha;
						uni.setStorageSync('uni-needCaptcha', this.needCaptcha)
						if (this.needCaptcha) {
							this.captcha('createCaptcha')
						}
					},
					fail: (e) => {
						uni.showModal({
							content: JSON.stringify(e),
							showCancel: false
						})
					}
				})
			},
			toMain(userName) {
				this.login(userName);
				uni.reLaunch({
					url: '../min_main/min_main',
				});
			},
			async captcha(action, args) {
				if (this.captchaing) return;
				// 验证不loading
				this.captchaing = true;
				let {result: res} = await uniCloud.callFunction({
					name: 'user-center',
					data: {
						action,
						params: {
							...captchaOptions,
							...args
						}
					}
				})
				this.captchaing = false;
				if (res.code === 0) {
					this.captchaBase64 = res.captchaBase64
				} else {
					uni.showToast({
						icon: 'none',
						title: res.message,
						duration: 1000
					})
				}
				return res;
			}
	}
};
4.3 注册请求
  • 对于用户名和密码的格式要求,需自己写。
  • 注意:注册时发送给云函数user-centerdata数据的格式data:{action:'register',params: 账号,密码}
  • 请求模板uniCloud.callFunction({name: 'user-center',data: {action: 'register',params: data})
gotoRegister() {
	uni.showLoading({
		title: '正在提交,请稍后'
	});
	const data = {
		username: this.username,
		password: this.password
	};
	uniCloud.callFunction({
		name: 'user-center',
		data: {
			action: 'register',
			params: data
		},
		success(e) {
			uni.hideLoading();
			if (e.result.code === 0) {
				uni.showToast({
					title: '注册成功'
				});
			uni.setStorageSync('uni_id_token', e.result.token);
			uni.setStorageSync('username', e.result.username);
			uni.reLaunch({
				url: '../main/main'
			});
			} else {
				uni.showModal({
					content: JSON.stringify(e.result),
					showCancel: false
				});
			}
		},
		fail(e) {
			uni.hideLoading();
			uni.showModal({
				content: JSON.stringify(e),
				showCancel: false
			});
		}
	});
}
4.4 修改密码页

请求模板uniCloud.callFunction({name: 'user-center',data: {action: 'updatePwd',params: data})
传递的参数是对象,{newPassword:123456,oldPassword:654321,uid:'用户ID'}

gotoCheck(e) {
	var that = this;
	uni.showLoading({
		title: '正在提交,请稍后'
	});
	e.newPassword = that.againVal;
	e.oldPassword = that.nameVal;
	e.uid = uni.getStorageSync('user_id');
	uniCloud.callFunction({
		name: 'user-center',
			data: {
				action: 'updatePwd',
				params: {
					...e
				}
			},
		success: (res) => {
			uni.hideLoading()
			if (res.result.code === 0) {
				uni.showModal({
					title: '提示',
					content: res.result.msg,
					showCancel: false,
					success: (res) => {
						if (res.confirm) {
							that.logout();
							uni.removeStorageSync('uni_id_token')
							uni.removeStorageSync('username')
							uni.reLaunch({
								url: '/pages/main/main'
							})
						}
					}
				});
			} else {
				uni.showToast({
					title: res.result.msg,
					icon: 'none',
					duration: 2000
				})
				}
			},
			fail: (e) => {
				uni.hideLoading()
				uni.showModal({
					content: '修改密码失败',
					showCancel: false
				})
			}
			})
		}
	}
4.4 补充
  • 请求user-center函数可以进一步封装,调用时只传参,比如action,params都可以传参。这里就不做精简演示了。
  • 删除登录记录的云函数,删除验证码云端记录。
  • 获取当前user_id的全部登录记录数据,筛选出create_date值不是最大的全部记录,逐一删除。
  • 登录成功后,删除集合 opendb-verify-codes的全部记录
4.4.1 云函数 removeSth
'use strict';
const db = uniCloud.database();
const dbCmd = db.command;
exports.main = async (event, context) => {
	if (Array.isArray(event)) {
		if (event.length===0) {
			const resList = await db.collection('uni-id-users')
				.where({
					username: dbCmd.neq('这里填管理员账号')
				})
				.get();
			let userArr = resList.data;
			return {
				msg: '查询用户列表,成功',
				code: 200,
				userArr
			}
		} else {
			event.forEach(k=>{
				db.collection('uni-id-users').doc(`${k}`).remove();
			})
			const resList = await db.collection('uni-id-users')
				.where({
					username: dbCmd.neq('这里填管理员账号')
				})
				.get();
			let userArr = resList.data;
			return {
				msg:'查询并删除',
				userArr
			}
		}
	} else{
		const {uid} = event;
		db.collection('opendb-verify-codes').where({
			  _id: dbCmd.exists(true)
			}).remove();
		let resList = await db.collection('uni-id-log')
			.where({
				user_id: `${uid}`
			})
			.get();
		let res = resList.data;
		if (res.length > 1) {
			let num = 0;
			res.forEach((item) => {
				if (item.create_date > num) {
					num = item.create_date;
				}
			})
			let resObjArr = await db.collection('uni-id-log')
				.where({
					create_date: dbCmd.neq(num)
				})
				.get();
			resObjArr.data.forEach(async (item) => {
				let resSucc = await db.collection('uni-id-log').doc(`${item._id}`).remove();
				console.log(resSucc);
			});
			const date = new Date().getTime();
			res = await db.collection('uni-id-log')
				.where({
					user_id: `${uid}`
				})
				.get();
			return {
				msg: '删除成功',
				code: 200
			}
		} else {
			return {
				msg: `当前账号仅有一次登录记录`,
				code: 200
			}
		}
	}
};
4.4.2 在common内创建 removeSth.js
const removeSth = (mydata) => {
	return new Promise((reslove, reject) => {
		uniCloud.callFunction({
			name: 'removeSth',
			data: mydata
		})
		.then(
		(res)=>{
			reslove(res.result)
		},
		(err)=>{
			reject(err)
		})
		.catch(err => {
			console.log(err);
		})
	});
};
export {
	removeSth
}
4.4.3 页面调用
import {removeSth} from "../../common/removeSth.js";

let uid = { uid: `${uni.getStorageSync('user_id')}` };

removeSth(uid).then(v=>{
	console.log(v);
})	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值