提示: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