uni-app小程序微信一鍵登錄實現過程記錄


話不多是,直接上代碼(我里面按鈕用到了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 必須是企業的,且需要完成微信認真,然后你是當前項目的開發人員。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM