话不多是,直接上代码(我里面按钮用到了vant的组件):
<template> <view style="height: 100vh;display: flex;flex-direction: column;align-items: center;justify-content: center;box-sizing: border-box;"> <van-button type="primary" block open-type="getUserInfo" @getuserinfo="appLoginWx"> 微信一键登录 </van-button> <van-button v-show="showPhone" type="primary" block open-type="getPhoneNumber" @getphonenumber="getPhone"> 授权电话 </van-button> </view> </template> <script> const WXBizDataCrypt = require(\'@/utils/WXBizDataCrypt\') export default { data() { return { appId:\'******************\', // 小程序的appId(注意需要企业的appId,并且你是开发人员,不然后续无法获取到手机号码) showPhone: false, userInfo: {}, sessionKey: null, unionid: null, openId: null, phone: null } }, methods: { // 授权获取微信用户信息 appLoginWx(res) { console.log(res) // 获取用户信息成功 if (res.detail.errMsg === \'getUserProfile:ok\' || res.detail.errMsg === \'getUserInfo:ok\') {this.userInfo = res.detail.userInfo; let _this = this; uni.showLoading({ title: \'获取用户信息...\', mask: true }); // 获取jsCode uni.login({ provider: \'weixin\', success(resLogin) { console.log(resLogin); if (resLogin.errMsg === "login:ok") { // 获取jsCode成功,通过jsCode调用微信api获取用户openId _this.wechatLogin(resLogin.code); return } uni.hideLoading(); uni.showToast({ title: \'获取用户信息失败,请重试\', icon: \'none\', duration: 2000 }); }, fail() { uni.hideLoading(); uni.showToast({ title: \'获取用户信息失败,请重试\', icon: \'none\', duration: 2000 }); } }); } }, wechatLogin(wxCode) { // 这里一般让后端去调用微信api获取openId等信息,前端调用的话像会多下面这个请求 // 因为若果是后端去调用的话,后端拿到微信api返回的openId后可直接去数据库查询判断该用户是否已注册, // 如果已经注册了就直接返回注册的用户信息, // 如果未注册,则后端需要返回openId、sessionKeyde等信息, // 然后前端页面弹出授权获取手机号码的按钮,用户点击后拿到手机号后进行解密后再把信息提交给后台进行注册 const params = { appid: this.appId, // 小程序的appId(注意需要企业的appId,并且你目前是开发人员,不然后续无法获取到手机号码) secret: \'***************\', // 企业小程序的secret js_code: wxCode, // 注意jsCode动态获取的,使用一次后将失效 grant_type: \'authorization_code\' // 这个参数固定写死 } // 调用微信api获取openid等信息 this.$get(\'https://api.weixin.qq.com/sns/jscode2session\', params).then(res => { console.log(res) if (res.errcode) { console.log(\'获取openId失败\') uni.hideLoading(); uni.showToast({ title: \'获取用户信息失败\', icon: \'none\', duration: 2000 }); return } this.openId = res.openid this.sessionKey = res.session_key this.unionid = res.unionid // 调用后端接口判断用户是否已注册过 this.$post(\'/login\', { openId: this.openId }).then(res => { uni.hideLoading(); // 若返回的参数中有token说明已经注册过 if (res.status === 200 && res.data.token) { uni.showToast({ title: \'登录成功!\', duration: 1000 }); // 缓存用户信息 uni.setStorageSync("token", res.data.token); uni.setStorageSync("userInfo", res.data); // 登录成功返回上一页 setTimeout(() => { uni.navigateBack({ delta: 1 }) }, 1000) return } // 走到这里说明没有注册过,需要弹出授权获取用户手机号的弹框按钮让用户授权 if (res.status == 200) { this.showPhone = true return } uni.showToast({ title: res.message, icon: \'none\', duration: 2000 }); }).catch(() => { uni.hideLoading(); uni.showToast({ title: \'登录失败,请稍后重试\', icon: \'none\', duration: 2000 }); }) }).catch(err => { console.log(err) uni.hideLoading(); uni.showToast({ title: \'获取用户信息失败\', icon: \'none\', duration: 2000 }); }) // 下面注释的就是后端去调用微信api获取用户openId的提供给前端的接口 // this.$post(\'/login\', { // jsCode: wxCode // }).then(res => { // console.log(res); // uni.hideLoading(); // // 若直接返回token说明已经注册 // if (res.status === 200 && res.data.token) { // uni.showToast({ // title: \'登录成功!\', // duration: 1000 // }); // uni.setStorageSync("token", res.data.token); // this.saveUserInfo(res.data); // setTimeout(() => { // // this.goTabBar(\'/pages/index\') // uni.navigateBack({ // delta: 1 // }) // }, 1000) // return // } // if (res.status == 200) { // this.openId = res.data.openid // this.sessionKey = res.data.session_key // this.unionid = res.data.unionid // this.id = res.data.id // this.showPhone = true // return // } // uni.showToast({ // title: res.message, // icon: \'none\', // duration: 2000 // }); // }).catch(() => { // uni.hideLoading(); // uni.showToast({ // title: \'登录失败,请稍后重试\', // icon: \'none\', // duration: 2000 // }); // }) }, // 授权电话号回调 (这里千万注意:小程序必须要完成 微信认证才能获取到加密的手机号码) getPhone(res) { console.log(res) if (res.detail.errMsg === \'getPhoneNumber:ok\') { const encryptedData = res.detail.encryptedData console.log(123, sessionKey, encryptedData, iv) const pc = new WXBizDataCrypt(this.appId, this.sessionKey) const data = pc.decryptData(encryptedData, res.detail.iv) // 这里使用解密手机号的方法 console.log(\'解密后 data: \', data.phoneNumber) this.phone = data.phoneNumber this.showPhone = false this.loginHandle() } else { this.showPhone = false uni.showToast({ title: \'获取手机号失败,请重试\', icon: \'none\', duration: 2000 }); } }, // 用户注册 loginHandle() { const data = { "account": this.phone, "icon": this.userInfo.avatarUrl, "id": this.id, "nickname": this.userInfo.nickName, "openId": this.openId, "phone": this.phone, "unionid": this.unionid } console.log(data) uni.showLoading({ title: \'登录中...\', mask: true }); this.$post(\'/login/login\', data).then(res => { console.log(res); uni.hideLoading(); if (res.status == 200) { uni.showToast({ title: \'登录成功!\', duration: 1000 }); uni.setStorageSync("token", res.data.token); uni.setStorageSync("userInfo", res.data); setTimeout(() => { uni.navigateBack({ delta: 1 }) }, 1000) } else { uni.showToast({ title: res.message, icon: \'none\', duration: 2000 }); } }); }, } } </script> <style> </style>
以下是上面解密手机号方法的封装,我是放在utils目录下的:
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
注意事项:想要获取到手机号并成功解密的话,appId 必须是企业的,且需要完成微信认真,然后你是当前项目的开发人员。