微信小程序登录获取手机号前端解密

提示:secret不能暴露在前端

uniapp 微信小程序登录获取手机号前端解密


前言

记录一下代码


<template>
	<view class="main--height">
		<view class="login">
			<image class="photo" :src="userInfo.nickName?userInfo.avatarUrl:'/static/logo.png'" mode=""></image>
			<view class="title">
				{{userInfo.nickName?userInfo.nickName:'欢迎使用'}}
			</view>
			<view class="text-c">
				<text v-if="!userInfo.nickName"></text>
				<text v-else>亲,已授权登录,快去同步会员信息吧!</text>
			</view>
			<view class="login-view">
				<button @click.stop="getUserInfo" color="#DE182B" v-if="!userInfo.nickName">
					微信授权
				</button>
				<button open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber" color="#DE182B" v-else>
					微信手机号登录
				</button>
			</view>

			<view class="protocol">
				<view class="" @tap="checkState = !checkState">
					<radio color="#DE182B" class="red" :checked="checkState" style="transform: scale(0.7);" />
					<text>登录则表示同意<text @tap="navTo">《平台用户服务条款》</text></text>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import WXBizDataCrypt from "@/utils/WXBizDataCrypt.js";
	import {
		login
	} from "@/api/login.js"
	export default {
		data() {
			return {
				checkState: false,
				openType: '',
				jsCode: '',
				openid: '',
				unionid: '',
				session_key: '',
				userInfo: {},
				loginStatus: false
			};
		},
		watch: {
			checkState(newValue) {
				console.log(newValue);
				if (newValue) this.openType = 'getPhoneNumber'
				else this.openType = ''
			}
		},
		onLoad() {
			this.initLogin()
			console.log(this.$store);
		},
		methods: {
			initLogin() {
				uni.login({
					success: (res) => {
						if (res.code) { //微信登录成功 已拿到code  
							this.jsCode = res.code //保存获取到的code  
							console.log(res.code);
							uni.request({
								url: 'https://api.weixin.qq.com/sns/jscode2session',
								method: 'GET',
								data: {
									appid: '', //你的小程序的APPID  
									secret: '', //你的小程序的secret,  
									js_code: res.code, //wx.login 登录成功后的code  
									grant_type: 'authorization_code'
								},
								success: (cts) => {
									// 换取成功后 暂存这些数据 留作后续操作  
									this.openid = cts.data.openid //openid 用户唯一标识  
									this.unionid = cts.data.unionid //unionid 开放平台唯一标识  
									this.session_key = cts.data.session_key //session_key  会话密钥  
								}
							});
						} else {
							console.log('登录失败!' + res.errMsg)
						}
					}
				})
			},

			getUserInfo() {
				if (!this.checkState) return uni.showToast({
					icon: "none",
					title: "请阅读并勾选用户协议"
				})
				let that = this
				uni.getUserProfile({
					desc: "获取用户信息",
					success(e) {
						console.log(e);
						that.userInfo = e.userInfo
						that.loginStatus = true

					},
					fail(e) {
						that.loginStatus = false
						uni.showToast({
							icon: "none",
							title: "已取消登录"
						})
					}
				})
			},
			async onGetPhoneNumber(e) {

				// if (!this.loginStatus) return uni.showToast({
				// 	icon: "none",
				// 	title: "未授权,登录失败"
				// })
				if (e.detail.errMsg == "getPhoneNumber:fail user deny") { //用户决绝授权  
					//拒绝授权后弹出一些提示  
					uni.showToast({
						icon: "none",
						title: "已取消登录"
					})
				} else { //允许授权  

					if (!this.checkState) return uni.showToast({
						icon: "none",
						title: "请阅读并勾选用户协议"
					})
					// e.detail.encryptedData //加密的用户信息  
					// e.detail.iv //加密算法的初始向量  时要用到 
					let pc = new WXBizDataCrypt('wxXXXXXXX', this.session_key); //wxXXXXXXX为你的小程序APPID  
					let data = pc.decryptData(e.detail.encryptedData, e.detail.iv);
					console.log(data);
					this.userInfo.phone = data.phoneNumber
					this.userInfo.openId = this.openid
					this.userInfo.sessionKey = this.session_key
					console.log('userInfo', this.userInfo);
					let result = await login(this.userInfo)
					console.log('获取登录信息', result);
					if (result.code == 200) {
						this.$store.commit('SET_USER_INFO', result.data.jyCmsWxJcAccountVo)
						this.$store.commit('SET_TOKEN', result.data.token)
						this.navigateTo()
					} else {
						this.$kit.toast(result.msg)
					}
				}
			},
			navigateTo() {
				console.log('跳转首页');
				uni.switchTab({
					url: '/pages/tabbar/frontpage'
				})
			}
		}
	};
</script>

<style lang="scss">
	.login {
		position: absolute;
		top: 17%;
		width: 100%;
		display: flex;
		flex-direction: column;
		align-items: center;

		.photo {
			width: 70px;
			height: 70px;
			background: #c4c4c4;
			border-radius: 50%;
		}

		.title {
			font-size: 16px;
			color: #333333;
			font-weight: bold;
			margin-top: 17px;
		}

		.van-button {
			width: 310px;
			height: 44px;
			background: #65d366;
		}

		.protocol {
			font-size: 13px;
			color: #bababa;
			margin-top: 20px;
			display: flex;
			align-items: center;
			position: fixed;
			bottom: 60rpx;

			.checkbox_text {
				font-size: 13px;
				color: #bababa;
			}

			.van-checkbox__icon--checked {
				background-color: #62C163;
				border-color: #62C163;
			}
		}

		.text-c {
			padding: 100rpx 80rpx 60rpx;
			text-align: center;

			text {
				font-size: 26rpx;
				color: #999999;
			}
		}

		.login-view {

			button {
				width: 680rpx;
				background-color: #DE182B;
				color: #ffffff;
				border-radius: 10rpx;
			}
		}
	}
</style>

WXBizDataCrypt.js解密文件内容

var crypto = require('crypto')

function WXBizDataCrypt(appId, sessionKey) {
  this.appId = appId
  this.sessionKey = sessionKey
}

WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
  // base64 decode
  var sessionKey = new Buffer(this.sessionKey, 'base64')
  encryptedData = new Buffer(encryptedData, 'base64')
  iv = new Buffer(iv, 'base64')

  try {
     // 解密
    var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
    // 设置自动 padding 为 true,删除填充补位
    decipher.setAutoPadding(true)
    var decoded = decipher.update(encryptedData, 'binary', 'utf8')
    decoded += decipher.final('utf8')
    
    decoded = JSON.parse(decoded)

  } catch (err) {
    throw new Error('Illegal Buffer')
  }

  if (decoded.watermark.appid !== this.appId) {
    throw new Error('Illegal Buffer')
  }

  return decoded
}

module.exports = WXBizDataCrypt

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,可以得知获取微信小程序用户手机号的方法有两种,分别是新版和老版。下面分别介绍这两种方法: 1. 新版获取用户手机号的方法: 前端需要授权两次,一次获取用户信息授权码code,另外一次获取用户手机授权码code,全部传给后端。后端通过用户信息授权码获取openid,通过手机授权码获取手机号码。具体步骤如下: - 前端调用wx.login()方法获取用户信息授权码code和用户手机授权回调里的iv和encryptedData。 - 前端调用wx.getPhoneNumber()方法获取用户手机号授权码code。 - 前端获取到的code和iv、encryptedData一起传给后端。 - 后端通过用户信息授权码code获取openid,通过手机授权码获取手机号码。 - 后端将获取到的手机号码进行绑定用户,然后通过登录验证返回给前端登录凭证token。 2. 老版获取用户手机号的方法: 前端需要传给后端授权码code和用户手机授权回调里的iv和encryptedData。后端通过code获取openid和sessionKey,然后用sessionKey和iv解密encryptedData获取手机号。最后通过手机号进行绑定用户,然后通过登录验证返回给前端登录凭证token。具体步骤如下: - 前端调用wx.login()方法获取用户信息授权码code和用户手机授权回调里的iv和encryptedData。 - 前端获取到的code和iv、encryptedData一起传给后端。 - 后端通过code获取openid和sessionKey。 - 后端用sessionKey和iv解密encryptedData获取手机号。 - 后端将获取到的手机号码进行绑定用户,然后通过登录验证返回给前端登录凭证token。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值