整体思路:
接口获取openId => 用户微信信息入库 => 手机号授权入库
逻辑详解:
我们知道小程序都是需要openId的,那我们可以通过前端获取,也可以通过后端接口获取,
前端就是这个地址,appid和secret 在你微信公众平台下都可以找到, code,在你调用uni.login就可以获取,但是切记,code码只能使用一次,你在开发环境时可以使用下面链接来前端获取openId,但是在线上生产环境,就要切换成后端接口获取了,因为会被小程序服务器域名所限制。
https://api.weixin.qq.com/sns/jscode2session?appid=' +
appid + '&secret=' + secret + '&js_code=' + code +
'&grant_type=authorization_code
获取到openId的目的,就是判断你数据库里是否有该用户,在小程序里,openId就是唯一主键的意思,然后下一步就是获取你的微信昵称和头像,那么这个要调用
uni.getUserProfile()
大家一定要用这个api来获取微信信息,否则其他获取的是假的用户信息 !
获取手机号授权,这个必须要求你在微信公众平台申请哦,否则是没有这个权限的,另外大家可能有疑问,微信信息授权和手机号授权为啥不写在一起? 因为手机号授权只能通过button按钮,并且使用open-type来获取,这一点,uniapp和微信原生是一致的,而且这个获取手机号的按钮,必须用户主动去点击喔,所以这也是我为啥将他写在遮盖层上了。
<button type="primary" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">绑定手机号</button>
手机号和微信用户信息这样都拿到了,那你就可以完成自己想要的操作了,那么又有同学想问,那我想获取身份证信息咋办? 那我明确告诉你,取不到!那有没有类似的呢,可以通过百度ocr识别来将前端传上去的身份证照片进行验证识别,这一点,我下一篇博客将会写上去?。
部分截图:
点击授权登录,将会弹出微信用户信息授权,然后会出现获取手机号按钮的遮盖层,点击获取手机号授权
?
?
所有代码:
这里简单说一下, proxy.$api.user.xxx, 这是我调用接口的方式,大家可以根据自己想要方式来实现uni.request,这一点没有啥强制性要求
<template>
<view>
<view>
<view>
<view class="header">
<image src="/static/img/login-wx.png"></image>
</view>
<view class="content">
<view>申请获取以下权限</view>
<text>获得你的公开信息(昵称,头像、地区等)</text>
</view>
<button class="bottom" type="primary" :disabled="userInfoDisabled" @click="wxGetUserInfo">授权登录</button>
</view>
</view>
<van-overlay :show="overlayShow">
<view class="login-wrapper">
<view class="login-bottom">
<button type="primary" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">绑定手机号</button>
</view>
</view>
</van-overlay>
</view>
</template>
<script setup>
import {
ref,
reactive,
getCurrentInstance
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app'
const {
proxy
} = getCurrentInstance()
const appid = "xxx"
const secret = "xxx"
const userInfoDisabled = ref(false)
const userInfo = reactive({
thirdAppType: 1,
thirdUserId: "",
nickName: '',
wechatPicture: ''
})
const sessionKey = ref('') // session码
const pageOption = ref()
const overlayShow = ref(false)
const wxGetUserInfo = () => {
if (uni.getUserProfile) {
uni.getUserProfile({
desc: 'Wexin', // 这个参数是必须的
success: result => {
uni.showLoading({
title: '授权中...'
});
userInfoDisabled.value = true
userInfo.nickName = result.userInfo.nickName
userInfo.wechatPicture = result.userInfo.avatarUrl
proxy.$api.user.login({
thirdAppType: userInfo.thirdAppType,
thirdUserId: userInfo.thirdUserId,
nickName: userInfo.nickName,
wechatPicture: userInfo.wechatPicture
}).then(res => {
userInfoDisabled.value = false
uni.hideLoading();
if (res.data.bindSpecialCode == 203) {
uni.setStorageSync('id', res.data.id);
uni.setStorageSync('nickName', res.data.nickName);
uni.setStorageSync('wechatPicture', res.data.wechatPicture);
overlayShow.value = true
return
} else {
uni.showToast({
title: '登录成功'
})
uni.setStorageSync('id', res.data.id);
uni.setStorageSync('nickName', res.data.nickName);
uni.setStorageSync('wechatPicture', res.data.wechatPicture);
uni.setStorageSync('tel', res.data.tel.data);
// 然后跳回原页面
if (pageOption.value.backtype == 1) {
uni.redirectTo({
url: '/pages/home/index'
})
} else {
uni.switchTab({
url: '/pages/home/index'
})
}
}
}).catch(e => {
userInfoDisabled.value = false
uni.hideLoading();
uni.showToast({
title: '用户信息操作失败',
icon: 'none'
});
})
},
fail: res => {
console.log('用户拒绝授权信息');
}
})
} else {
uni.showToast({
title: '获取用户信息失败',
icon: 'none'
});
}
}
const login = () => {
uni.showLoading({
title: '登录中...'
});
uni.login({
provider: 'weixin',
success: loginRes => {
let code = loginRes.code;
proxy.$api.user.getOpenId({
appid,
secret,
code
}).then(res => {
if (res.code == 200) {
getOpenId(res.data)
}
}).catch(e => {
uni.hideLoading();
uni.showToast({
title: '获取 OpenId 失败',
icon: 'none'
});
userInfoDisabled.value = false
})
},
fail: () => {
uni.hideLoading();
uni.showToast({
title: '获取 code 失败',
icon: 'none'
});
userInfoDisabled.value = false
return false;
}
});
return false;
}
const getOpenId = (codeRes) => {
let openId = codeRes.openid;
sessionKey.value = codeRes.sessionKey;
userInfo.thirdUserId = openId
proxy.$api.user.openIdParse({
thirdAppType: userInfo.thirdAppType,
thirdUserId: openId
}).then(res => {
uni.hideLoading();
uni.setStorageSync('openId', openId);
userInfoDisabled.value = false
// 用户信息未授权入库
if (res.data.bindSpecialCode == 202) {
uni.showToast({
title: '请点击授权登录',
icon: 'none'
});
// 用户手机号未授权入库
} else if (res.data.bindSpecialCode == 203) {
overlayShow.value = true
uni.setStorageSync('id', res.data.id);
uni.setStorageSync('nickName', res.data.nickName);
uni.setStorageSync('wechatPicture', res.data.wechatPicture);
} else {
uni.showToast({
title: '登录成功'
})
uni.setStorageSync('id', res.data.id);
uni.setStorageSync('nickName', res.data.nickName);
uni.setStorageSync('wechatPicture', res.data.wechatPicture);
uni.setStorageSync('tel', res.data.tel.data);
if (pageOption.value.backtype == 1) {
uni.redirectTo({
url: '/pages/home/index'
})
} else {
uni.switchTab({
url: '/pages/home/index'
})
}
}
}).catch(e => {
uni.hideLoading();
uni.showToast({
title: '获取授权信息失败',
icon: 'none'
});
userInfoDisabled.value = false
})
}
/**
* 手机号授权
*/
const getPhoneNumber = (e) => {
if (e.detail.errMsg == 'getPhoneNumber:fail user deny') {
console.log('用户拒绝提供手机号');
} else {
let encryptedData = e.detail.encryptedData
let iv = e.detail.iv
overlayShow.value = false
if (encryptedData && iv) {
bindTelApi(encryptedData, iv)
}
}
}
const bindTelApi = (encryptedData, iv) => {
uni.showLoading({
title: '绑定手机号中...'
});
proxy.$api.user.bindTel({
encryptedData: encryptedData,
iv: iv,
sessionKey: sessionKey.value,
uid: uni.getStorageSync('id')
}).then(res => {
uni.hideLoading()
if (res.code == 200) {
uni.setStorageSync('tel', res.data.tel.data);
uni.switchTab({
url: '/pages/home/index'
})
}
}).catch(e => {
uni.hideLoading()
})
}
onLoad((options) => {
pageOption.value = options
const {
proxy
} = getCurrentInstance()
const loginStatus = proxy.checkLogin('/pages/home/index', 2)
if (!loginStatus) {
userInfoDisabled.value = true
login();
} else {
uni.switchTab({
url: '/pages/home/index'
})
}
})
</script>
<style lang="scss" scoped>
.header {
margin: 160rpx 0 60rpx 50rpx;
text-align: center;
width: 650rpx;
image {
width: 180rpx;
height: 180rpx;
}
}
.content {
margin-bottom: 68rpx;
text-align: center;
text {
display: block;
color: #9d9d9d;
margin-top: 20rpx;
}
}
.bottom {
border-radius: 80rpx;
margin: 70rpx 50rpx;
font-size: 35rpx;
}
.login-wrapper{
height: 100%;
position: relative;
.login-bottom{
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 133rpx;
background-color: #fff;
button{
position: absolute;
top: 50%;
left: 50%;
background-color: #CA2915;
transform: translate(-50%, -50%);
border-radius: 30px;
width: 435rpx;
height: 68rpx;
line-height: 68rpx;
}
}
}
</style>
|