使用 UniApp 实现小程序的微信登录功能


Posted in Javascript onJune 09, 2020

1.微信登录思路:

  • 在main.js 中封装公共函数,用于判断用户是否登录
  • 在main.js 中分定义全局变量,用于存储接口地址
  • 如果没有登录、则跳转至登录页面
  • 进入登录页面
  • 通过 wx.login 获取用户的 code
  • 通过 code 获取用户的 SessionKey、OpenId 等信息【本应后台接口、但是此处使用js发送请求】
  • 通过 openId 调用后台 Api 获取用户的信息
  • 获取成功,则说明已经授权过了,直接登录成功
  • 获取失败,则说明没有授权过,需要授权之后才能进行登录
  • 用户点击页面微信登录按钮【 <button open-type="getUserInfo"></button>】
  • 获取用户数据,然后调用后台接口写入数据库

2.在 applets/main.js 中添加如下

// 封装全局登录函数
// backpage, backtype 2个参数分别代表:
// backpage : 登录后返回的页面
// backtype : 打开页面的类型[1 : redirectTo 2 : switchTab]
Vue.prototype.checkLogin = function( backpage, backtype ){
	// 同步获取本地数据(uid、随机码、用户名、头像)
	var user_id = uni.getStorageSync('user_id');
	var user_nu = uni.getStorageSync('user_nu');
	var user_nm = uni.getStorageSync('user_nm');
	var user_fa = uni.getStorageSync('user_fa');
	if( user_id == '' || user_nu == '' || user_fa == ''){
		// 使用重定向的方式跳转至登录页面
		uni.redirectTo({url:'../login/login?backpage='+backpage+'&backtype='+backtype});
		return false;
	}
	// 登录成功、已经登录返回数组 [用户 id, 用户随机码, 用户昵称, 用户表情]
	return [user_id, user_nu, user_nm, user_fa];
}
// 定义一个全局的请求地址
Vue.prototype.apiServer = 'http://0608.cc/'

3.在 pages/login/login.vue 中添加如下

<template>
	<view>
		<!-- login view html start -->
		<view>
			<view>
				<view class="header"><image src="/static/img/public/login-wx.png"></image></view>
				<view class="content">
					<view>申请获取以下权限</view>
					<text>获得你的公开信息(昵称,头像、地区等)</text>
				</view>
				<button class="bottom" type="primary" open-type="getUserInfo" withCredentials="true" lang="zh_CN" @getuserinfo="wxGetUserInfo">授权登录</button>
			</view>
		</view>
		<!-- login view html end -->
	</view>
</template>

<script>
export default {
	data() {
		return {
			appid: '*************',
			secret: '*************************',
			code: '',
			sessionKey: '',
			openId: '',
			userInfo: {
				avatarUrl: '',
				city: '',
				country: '',
				gender: 1,
				language: '',
				nickName: ''
			},
			pageOption: {}
		};
	},
	methods: {
		// 第一授权获取用户信息 ===》按钮触发
		wxGetUserInfo() {
			let _self = this;
			// 1.获取用户的信息
			uni.getUserInfo({
				provider: 'weixin',
				success: ( infoRes ) => {
					console.log( infoRes )
					_self.userInfo = infoRes.userInfo
					// 2.提交数据到后台、写入数据库
					uni.request({
						url: _self.apiServer + 'appletsUserInfo',
						data: {
							openid: _self.openId,
							avatarUrl: _self.userInfo.avatarUrl,
							city: _self.userInfo.city,
							country: _self.userInfo.country,
							gender: _self.userInfo.gender,
							language: _self.userInfo.language,
							nickName: _self.userInfo.nickName
						},
						method: 'POST',
						success: res => {
							if( res.data.code != 0 )
							{
								uni.showToast({ title: res.data.msg, icon: 'none' });
								return false;
							}
							// 用户信息写入缓存
							uni.showToast({title: '登录成功'})
							uni.setStorageSync( 'user_id', res.data.res.u_id );
							uni.setStorageSync( 'user_nm', res.data.res.u_nickName );
							uni.setStorageSync( 'user_fa', res.data.res.u_avatarUrl );
							uni.setStorageSync( 'user_nu', res.data.res.u_regtime );
							// 然后跳回原页面
							if( _self.pageOption.backtype == 1 )
							{
								uni.redirectTo({ url: _self.pageOption.backpage })
							}else{
								uni.switchTab({ url: _self.pageOption.backpage })
							}
						},
						fail: () => {
							uni.showToast({ title: '用户信息操作失败', icon: 'none' });
						}
					});
				},
				fail: () => {
					uni.showToast({ title: '获取用户信息失败', icon: 'none' });
				}
			});
			return false
		},
		// 登录
		login() {
			let _self = this;

			// 0. 显示加载的效果
			uni.showLoading({
				title: '登录中...'
			});

			// 1. wx 获取登录用户 code
			uni.login({
				provider: 'weixin',
				success: loginRes => {
					console.log(loginRes);
					_self.code = loginRes.code;
					// 2. 将用户登录code传递到后台置换用户SessionKey、OpenId等信息
					uni.request({
						url:
							'https://api.weixin.qq.com/sns/jscode2session?appid=' +
							_self.appid +
							'&secret=' +
							_self.secret +
							'&js_code=' +
							_self.code +
							'&grant_type=authorization_code',
						success: codeRes => {
							console.log(codeRes);
							_self.openId = codeRes.data.openid;
							_self.sessionKey = codeRes.data.session_key;
							// 3.通过 openId 判断用户是否授权
							uni.request({
								url: _self.apiServer + 'loginApplets',
								data: {
									openid: _self.openId
								},
								method: 'POST',
								success: openIdRes => {
									console.log(openIdRes);
									// 隐藏loading
									uni.hideLoading();
									// 还没授权登录、请先授权然后登录
									if (openIdRes.data.code == 1) {
										// 提示消息、让用户授权
										uni.showToast({ title: openIdRes.data.msg, icon: 'none' });
									}
									// 已经授权了、查询到用户的数据了
									if (openIdRes.data.code == 0) {
										// 用户信息写入缓存
										uni.showToast({title: '登录成功'})
										uni.setStorageSync( 'user_id', openIdRes.data.res.u_id );
										uni.setStorageSync( 'user_nm', openIdRes.data.res.u_nickName );
										uni.setStorageSync( 'user_fa', openIdRes.data.res.u_avatarUrl );
										uni.setStorageSync( 'user_nu', openIdRes.data.res.u_regtime );
										// 然后跳回原页面
										if( _self.pageOption.backtype == 1 )
										{
											uni.redirectTo({ url: _self.pageOption.backpage })
										}else{
											uni.switchTab({ url: _self.pageOption.backpage })
										}
									}
								},
								fail: () => {
									uni.showToast({ title: '获取授权信息失败', icon: 'none' });
									return false;
								}
							});
						},
						fail: () => {
							uni.showToast({ title: '获取 SesssionKey OpenId 失败', icon: 'none' });
							return false;
						}
					});
				},
				fail: () => {
					uni.showToast({ title: '获取 code 失败', icon: 'none' });
					return false;
				}
			});
			return false;
		}
	},
	onLoad( options ) {
		// 接收跳转的参数
		this.pageOption = options
		//默认加载
		this.login();
	}
};
</script>

<style>
.header {
	margin: 90rpx 0 90rpx 50rpx;
	border-bottom: 1px solid #ccc;
	text-align: center;
	width: 650rpx;
	height: 300rpx;
	line-height: 450rpx;
}

.header image {
	width: 200rpx;
	height: 200rpx;
}

.content {
	margin-left: 50rpx;
	margin-bottom: 90rpx;
}

.content text {
	display: block;
	color: #9d9d9d;
	margin-top: 40rpx;
}

.bottom {
	border-radius: 80rpx;
	margin: 70rpx 50rpx;
	font-size: 35rpx;
}
</style>

在 pages/my/my.vue 中添加如下:

<template>
	<view>我的页面</view>
</template>

<script>
var loginRes;
export default {
	data() {
		return {};
	},
	onLoad() {
		// 加载定义好的方法
		loginRes = this.checkLogin('../my/my', 2);
		// 没有登录成功,返回空
		if (!loginRes) {
			return;
		}
	},
	methods: {}
};
</script>

<style></style>

5.PHP 接口 loginApplets

public function loginApplets(Request $request, UserInfo $userInfo)
{
 // 获取数据
 $data['u_openid'] = $request->param('openid', '');
 // 验证数据
 $rule = [
  'u_openid' => 'require|max:200|min:10'
 ];
 $message = [
  'u_openid.require' => 'openid 不能为空',
  'u_openid.max'  => 'openid 格式错误',
  'u_openid.min'  => 'openid 格式错误'
 ];
 $validate = Validate::rule($rule)->message($message);
 if (!$validate->check($data)) {
  return json(['code' => 1, 'msg' => $validate->getError(), 'res' => null]);
 }
 // 根据 openid 判断是否存在
 $where['u_openid'] = $data['u_openid'];
 $user = $userInfo->selOne($where);
 if (!$user) {
  return json(['code' => 1, 'msg' => '还没授权登录、请先授权然后登录', 'res' => $user]);
 }
 return json(['code' => 0, 'msg' => '已授权获取到用户的数据', 'res' => $user]);
}

6.PHP 接口 appletsUserInfo

public function appletsUserInfo(Request $request, UserInfo $userInfo)
{
 // 获取数据
 $data['u_openid'] = $request->param('openid', '');
 $data['u_avatarUrl'] = $request->param('avatarUrl', '');
 $data['u_city'] = $request->param('city', '');
 $data['u_country'] = $request->param('country', '');
 $data['u_gender'] = $request->param('gender', '');
 $data['u_language'] = $request->param('language', '');
 $data['u_nickName'] = $request->param('nickName', '');
 // 验证数据
 $rule = [
  'u_openid' => 'require|max:200|min:10',
  'u_avatarUrl' => 'require',
  'u_nickName' => 'require'
 ];
 $message = [
  'u_openid.require'  => 'openid 不能为空',
  'u_openid.max'   => 'openid 格式错误',
  'u_openid.min'   => 'openid 格式错误',
  'u_avatarUrl.require' => '用户头像 不能为空',
  'u_nickName.max'  => '用户名 格式错误',
 ];
 $validate = Validate::rule($rule)->message($message);
 if (!$validate->check($data)) {
  return json(['code' => 1, 'msg' => $validate->getError(), 'res' => null]);
 }

 // 根据 openid 判断是否存在
 $where['u_openid'] = $data['u_openid'];
 $user = $userInfo->selOne($where);

 // 存在、执行修改
 if ($user) {
  $user_res = $userInfo->updOne($where, $data);
  $res = [];
  $res['u_id'] = $user['u_id'];
  $res['u_regtime'] = $user['u_regtime'];
 }

 // 不存在、执行添加
 if (empty($user)) {
  $res = [];
  $res = $data;
  $res['u_regtime'] = time();
  $res['u_id'] = $userInfo->addOne($res);
 }

 // 判断是否添加成功
 if (empty($res['u_id'])) {
  return json(['code' => 1, 'msg' => '注册失败,返回重试', 'res' => null]);
 }
 return json(['code' => 0, 'msg' => 'ok', 'res' => $res]);
}

总结

到此这篇关于使用 UniApp 实现小程序的微信登录的文章就介绍到这了,更多相关使用 UniApp 实现小程序的微信登录内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
我的javascript 函数链之演变
Apr 07 Javascript
JavaScript自定义事件介绍
Aug 29 Javascript
零基础搭建Node.js、Express、Ejs、Mongodb服务器及应用开发入门
Dec 20 Javascript
基于jquery实现省市联动特效
Dec 17 Javascript
学习vue.js中class与style绑定
Dec 03 Javascript
ES6学习教程之对象的扩展详解
May 02 Javascript
react路由配置方式详解
Aug 07 Javascript
AngularJS实现的锚点楼层跳转功能示例
Jan 02 Javascript
详解vue.js移动端配置flexible.js及注意事项
Apr 10 Javascript
Vue函数式组件的应用实例详解
Aug 30 Javascript
js神秘的电报密码 哈弗曼编码实现
Sep 10 Javascript
使用React代码动态生成栅格布局的方法
May 24 Javascript
详解vue高级特性
Jun 09 #Javascript
vue实例的选项总结
Jun 09 #Javascript
微信小程序中的列表切换功能实例代码详解
Jun 09 #Javascript
vue项目或网页上实现文字转换成语音播放功能
Jun 09 #Javascript
浅谈vue的第一个commit分析
Jun 08 #Javascript
从零开始在vue-cli4配置自适应vw布局的实现
Jun 08 #Javascript
详解Vue Cli浏览器兼容性实践
Jun 08 #Javascript
You might like
php防止伪造的数据从URL提交方法
2014/06/27 PHP
摘自织梦CMS中的图片处理类
2015/08/08 PHP
php 生成加密公钥加密私钥实例详解
2017/06/16 PHP
PHP写API输出的时用echo的原因详解
2019/04/28 PHP
jQuery生成asp.net服务器控件的代码
2010/02/04 Javascript
jquery按回车提交数据的代码示例
2013/11/05 Javascript
js关于字符长度限制的问题示例探讨
2014/01/24 Javascript
开源的javascript项目Kissy介绍
2014/11/28 Javascript
Javascript URI 解析介绍
2015/03/15 Javascript
用NODE.JS中的流编写工具是要注意的事项
2016/03/01 Javascript
限制复选框最多选择项的实现代码
2016/05/30 Javascript
配置nodejs环境的方法
2017/05/13 NodeJs
Angular2安装angular-cli
2017/05/21 Javascript
vue.js移动端app之上拉加载以及下拉刷新实战
2017/09/11 Javascript
VsCode与Node.js知识点详解
2019/09/05 Javascript
详解vue中在父组件点击按钮触发子组件的事件
2020/11/13 Javascript
[00:03]DOTA2新版本PA至宝展示
2014/11/19 DOTA
在Python的Django框架中生成CSV文件的方法
2015/07/22 Python
Python常见异常分类与处理方法
2017/06/04 Python
Python中list查询及所需时间计算操作示例
2018/06/21 Python
Python中查看变量的类型内存地址所占字节的大小
2019/06/26 Python
Python Opencv任意形状目标检测并绘制框图
2019/07/23 Python
python 使用socket传输图片视频等文件的实现方式
2019/08/07 Python
通过字符串导入 Python 模块的方法详解
2019/10/27 Python
numpy数组做图片拼接的实现(concatenate、vstack、hstack)
2019/11/08 Python
Python常用模块os.path之文件及路径操作方法
2019/12/03 Python
django的模型类管理器——数据库操作的封装详解
2020/04/01 Python
Python使用monkey.patch_all()解决协程阻塞问题
2020/04/15 Python
详解如何在登录过期后跳出Ifram框架
2020/09/10 HTML / CSS
英国舒适型鞋履品牌:FitFlop
2017/05/17 全球购物
瑞典多品牌连锁店:Johnells
2021/01/13 全球购物
Java基础面试题
2014/07/19 面试题
信息部岗位职责
2013/11/12 职场文书
《水上飞机》教学反思
2014/04/10 职场文书
会计专业求职信
2014/08/10 职场文书
学校党支部承诺书
2015/04/30 职场文书