波多野吉不卡中文Av无码Av

      <strong id="fzzds"><track id="fzzds"></track></strong>
    1. <strong id="fzzds"></strong>
      <strong id="fzzds"></strong>
    2. <ruby id="fzzds"><bdo id="fzzds"><rp id="fzzds"></rp></bdo></ruby>
        <strike id="fzzds"></strike>
      1. 您現在的位置: 微信小程序 > 微信小程序開發 > 教程 >

        小程序、H5登錄授權、分享、支付流程

        來源:微信小程序 編輯:Yiyongtong.com 發布時間:2020-05-22 10:16熱度:

         

        前言

         

        對于前端來說,微信的 支付 、 分享 、 登錄 是一定要掌握的,今天這篇文章,主要對這三方面的流程進行詳細的介紹。主要內容如下:

        域名相關知識介紹

         

        該網站不安全,請不要輸入密碼
        

        微信小程序授權登錄流程

         

        op=>operation: openid判斷是否登錄授權
        op2=>operation: 根據wx.login獲取code
        op3=>operation: 調用服務端根據code換取openid
        op4=>operation: 通過用戶授權,獲取信息,存到數據庫
        op->op2->op3->op4
        復制代碼

        如果你從來沒有閱讀過小程序登錄授權的文檔,建議你看一下下面的地址:

        服務端官方文檔 客戶端文檔

        nodejs + 小程序實現授權登錄

         


        前端部分
        1. 根據本地是否有userId判斷是否登錄,如果沒有登錄,則獲取用戶的openid
        onLoad() {
           if(!this.data.userId) {
               this.getSession()
           }
        },
         getSession() {
           wx.login({
             success: (res) => {
               if (res.code) {
                 app.get(Api.getSession, {
                   code: res.code
                 }).then(res => {
                   store.setItem('openid', res.openid)
                 })
               }
             }
           })
         }復制代碼
        1. 點擊授權按鈕,發起登錄請求。
        getUserInfo(e) {
            let userInfo = e.detail.userInfo;
            userInfo.openid = store.getItem('openid')
            app.get(Api.login, {
                userInfo
            }).then(res => {
                store.setItem('userId', res.data.userId)
                this.setData({
                    userId: res.userId
                })
            })
        }復制代碼

        服務端部分

         

        在 config 里面,定義公用的 appid 和 appsecret

        module.exports = {
            wx: {
                appId: 'wx0ef10432747d8f57',
                appsecret: 'cc47a6127687e999a1dffa756ff83c0e'
            },
            mp: {
                appId: 'wx0691f1dcf6e5e231',
                appSecret: 'c7ed875e338120f15f49476a6596eb4f'
            }
        }復制代碼

        然后通過調用小程序 官方文檔 的接口,獲取到 appid 傳給客戶端

        let express = require('express');
        let router = express.Router();
        let request = require('request');
        let config = require('./config');
        let uril = require('./../../util/index')
        config = Object.assign({}, config.mp);
        
        router.get('/getSession', (req, res) => {
            let code = req.query.code
            if (!code) {
                res.json(uril.handleFail('code不能為空', 10001))
            }
            let sessionUrl = `https://api.weixin.qq.com/sns/jscode2session?appid=${config.appId}&secret=${config.appSecret}&js_code=${code}&grant_type=authorization_code`;
            request(sessionUrl, (err, response, body) => {
                let result = util.handleResponse(err, response, body)
                res.json(result)
            })
        })復制代碼

        登錄接口 的編寫

        // 小程序授權登錄
        router.get('/login',async function(req,res){
          let userInfo = JSON.parse(req.query.userInfo);
          if (!userInfo){
            // 如果接口沒有信息,則返回錯誤信息
            res.json(util.handleFail('用戶信息不能為空',10002))
          }else{
            // 查詢當前用戶是否已經注冊
            let userRes = await dao.query({ openid: userInfo.openid},'users_mp');
            if (userRes.code == 0){
              // 如果已經注冊,直接把查出來的信息返回給客戶端
              if (userRes.data.length >0){
                res.json(util.handleSuc({
                  userId: userRes.data[0]._id
                }))
              }else{
                // 如果這個用戶之前沒有注冊,則在數據庫插入用戶信息
                let insertData = await dao.insert(userInfo,'users_mp');
                if (insertData.code == 0){
                  let result = await dao.query({ openid: userInfo.openid }, 'users_mp');
                  res.json(util.handleSuc({
                    userId: result.data[0]._id
                  }))
                }else{
                  res.json(insertData);
                }
              }
            }else{
              res.json(userRes);
            }
          }
        })復制代碼

        上述代碼的 handleFail 和 handleResponse 是封裝的對數據的統一處理,如果有興趣,參見 github 地址。這里不展示代碼。

        需要注意的是,這種實現方式,獲取 openid 的行為放在后端實現了。如果放在前端實現也可以,但是會相對比較麻煩一點。此時,suerId就已經在數據庫存儲,并且在本地保存了,下次登錄的時候,如果有userId存在就不需要再次登錄了。

        H5的登錄授權和分享流程

         

        H5的登錄授權略有不同。如果用戶登錄授權頁面,發現該用戶沒有登錄授權,則需要跳轉到授權頁面。 官方文檔 給出的流程如下:

        1 第一步:用戶同意授權,獲取code2 第二步:通過code換取網頁授權access_token3 第三步:刷新access_token(如果需要)4 第四步:拉取用戶信息(需scope為 snsapi_userinfo)5 附:檢驗授權憑證(access_token)是否有效

        在項目中代碼如下:(這里代碼沒有實現刷新access_token和拉取用戶信息)

        頁面加載的時候,判斷是否已經授權。

        mounted(){
           this.checkUserAuth();
         },
        methods:{
        // 檢查用戶是否授權過
        checkUserAuth(){
          let openId = this.$cookie.get('openId');
          if(!openId){
            // 如果沒有登錄授權,則跳轉到微信提供的跳轉頁面。
            window.location.href = API.wechatRedirect;
          }else{
          // 如果用戶已經授權,則調用獲取微信配置信息接口
            this.getWechatConfig();
          }
        },復制代碼

        API.wechatRedirect:

        wechatRedirect:'/api/wechat/redirect?url=http%3A%2F%2Fm.51purse.com%2F%23%2Findex&scope=snsapi_userinfo',復制代碼

        「注意」

         

        • url地址需要 encodeURIComponent 編碼才可以。
        • m.51purse.com 需要與你在微信公眾號后臺配置的 授權域名 一致!

        nodejs 對登錄授權回調接口的實現主要是拿到客戶端的請求參數,請求微信提供的 接口

        // 用戶授權重定向
        router.get('/redirect',function (req,res) {
          let redirectUrl = req.query.url, scope = req.query.scope, callback = 'http://m.51purse.com/api/wechat/getOpenId';
          cache.put('redirectUrl', redirectUrl);
          // 獲取到客戶端帶過來的數據,請求微信接口
          let authorizeUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${config.appId}&redirect_uri=${callback}&response_type=code&scope=${scope}&state=STATE#wechat_redirect`;
          res.redirect(authorizeUrl);
        })
        復制代碼

        當用戶點擊 確認授權 之后,會執行跳轉 callbacl:http://m.51purse.com/api/wechat/getOpenId 。而這個接口也是node端實現的,具體內容如下:

        // 用code換取access_token的方法
        exports.getAccessToken = function(code){
          let token_url = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${config.appId}&secret=${config.appSecret}&code=${code}&grant_type=authorization_code`;
          return new Promise((resolve, reject) => {
            request.get(token_url, function (err, response, body) {
              let result = util.handleResponse(err, response, body);
              resolve(result);
            })
          });
        }
        
        
        // 根據code獲取用戶的OpenId
        router.get('/getOpenId',async function(req,res){
          let code = req.query.code;
          console.log("code:"+code);
          if(!code){
            res.json(util.handleFail('當前未獲取到授權code碼'));
          }else{
            // 用code換取access_token
            let result = await common.getAccessToken(code);
            if(result.code == 0){
              // 換取access_token成功
              let data = result.data;
              let expire_time = 1000 * 60 * 60 * 2;
              // 往客戶端寫入cookie:openId
              res.cookie('openId', data.openid, { maxAge: expire_time });
              let openId = data.openid;
              let userRes = await dao.query({ 'openid': openId },'users');
              if (userRes.code == 0){
                if (userRes.data.length>0){
                  // 從數據庫查找到用戶信息后,回調到客戶端的頁面
                  let redirectUrl = cache.get('redirectUrl');
                  res.redirect(redirectUrl);
                }else{
                  let userData = await common.getUserInfo(data.access_token, openId);
                  let insertData = await dao.insert(userData.data,'users');
                  if (insertData.code == 0){
                    // 從數據庫查找到用戶信息后,回調到客戶端的頁面
                    let redirectUrl = cache.get('redirectUrl');
                    res.redirect(redirectUrl);
                  }else{
                    // 返回錯誤信息
                    res.json(insertData);
                  }
                }
              }else{
                // 返回錯誤信息
                res.json(userRes);
              }
            }else{
              // 返回錯誤信息
              res.json(result);
            }
          }
        })
        復制代碼

        「注意」:上面的代碼為了簡單,刪除了一些不必要的代碼,如有興趣,訪問gitHub。

        H5分享流程

         

        同樣,如果你沒有閱讀過微信H5開發的 官方文檔 ,建議你先閱讀。關于分享,你應該閱讀以下內容:

        當再次回調到頁面的時候,從cookie已經拿到openId了??蛻舳藭^續執行下面的代碼。獲取到服務端返回的配置信息,從而初始化分享的功能。

        在這之前,你需要 npm install wx-jssdk

        // 這個信息統一定義在api.js中,這里為了方便,放在前面,便于查看。
        API.wechatConfig: /api/wechat/jssdk
        
        
        // 獲取微信配置信息
        getWechatConfig(){
          this.$http.get(API.wechatConfig+'?url='+location.href.split('#')[0]).then(function(response){
            let res = response.data;
            if(res.code == 0){
              let data = res.data;
              wx.config({
                debug: true, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。
                appId: data.appId, // 必填,公眾號的唯一標識
                timestamp: data.timestamp, // 必填,生成簽名的時間戳
                nonceStr: data.nonceStr, // 必填,生成簽名的隨機串
                signature: data.signature,// 必填,簽名
                jsApiList: data.jsApiList // 必填,需要使用的JS接口列表
              })
              wx.ready(()=>{
                util.initShareInfo(wx);
              })
            }
          })
        }復制代碼

        util/index.js 里面對分享的功能進行了封裝。

        export default {
          //獲取瀏覽器地址欄參數值
          getUrlParam(name){
            let reg = new RegExp('(^|&)'+name+'=([^&]*)');
            let r = window.location.search.substr(1).match(reg);
            if(r!=null)return decodeURIComponent(r[2]);
          },
          initShareInfo(wx){
            let shareInfo = {
              title: 'xxxx', // 分享標題
              desc: 'xxxx', // 分享描述
              link: 'http://m.51purse.com/#/index', // 分享鏈接,該鏈接域名或路徑必須與當前頁面對應的公眾號JS安全域名一致
              imgUrl: '', // 分享圖標
            }
            wx.onMenuShareAppMessage(shareInfo);
            wx.onMenuShareTimeline(shareInfo);
            wx.onMenuShareQQ(shareInfo);
            wx.onMenuShareQZone(shareInfo);
            // 下面兩種方法為新的方法,上面的方法將會被淘汰。
            wx.updateAppMessageShareData(shareInfo);
            wx.updateTimelineShareData(shareInfo);
          }
        }
        復制代碼

        nodejs端對 /wechat/jssdk 接口的實現如下:

        // common.getToken()方法 獲取基礎接口的Token
        
        exports.getToken = function(){
          let token = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${config.appId}&secret=${config.appSecret}`;
          return new Promise((resolve, reject)=>{
            request.get(token, function (err, response, body) {
              let result = util.handleResponse(err, response, body);
              resolve(result);
            })
          })
        }
        ----
        
        router.get('/jssdk',async function(req,res){
          let url = req.query.url;
          let result = await common.getToken();
          if (result.code == 0){
            let token = result.data.access_token;
            let params = {
              // 生成隨機字符串
              noncestr:util.createNonceStr(),
              // 生成時間戳
              timestamp:util.createTimeStamp(),
              url
            }
              let str = util.raw(params);
              console.log('str:::' + JSON.stringify(params))
              let sign = createHash('sha1').update(str).digest('hex');
              res.json(util.handleSuc({
                appId: config.appId, // 必填,公眾號的唯一標識
                timestamp: params.timestamp, // 必填,生成簽名的時間戳
                nonceStr: params.noncestr, // 必填,生成簽名的隨機串
                signature: sign,// 必填,簽名
                jsApiList: [
                  'updateAppMessageShareData',
                  'updateTimelineShareData',
                  'onMenuShareTimeline',
                  'onMenuShareAppMessage',
                  'onMenuShareQQ',
                  'onMenuShareQZone',
                  'chooseWXPay'
                ] // 必填,需要使用的JS接口列表
              }))
            }
          }else{
            res.json(result);
          }
        })復制代碼

        以上代碼主要獲得基礎的 token ,然后用基礎 token 結合簽名、時間戳、隨機數等相關的參數,返回給客戶端相應的參數。

        需要注意的是, 基礎token 和 accessToken 的區別。建議 參考文章 。

        到此,微信H5接入jssdk實現分享就已經完成了。

        小程序支付

         

        小程序支付前端流程

        • 獲取openId
        • 調起數字簽名

        后端支付流程

        • 拼接常規參數
        • 生成簽名
        • 拼接xml數據
        • 調用下單接口
        • 獲取預支付Id:prepay_id
        • 生成支付sdk
        • 定義回調接口,接受微信支付消息

        支付的主要邏輯在服務端

        下面把服務端的流程通過代碼的方式表述出來。首先在util中封裝了一些支付需要的公共方法

        /**
         * 公共函數定義
         */
        let createHash = require('create-hash');
        module.exports = {
          // 生成隨機數
          createNonceStr(){
            return Math.random().toString(36).substr(2,15);
          },
          // 生成時間戳
          createTimeStamp(){
            return parseInt(new Date().getTime() / 1000) + ''
          },
          // 生成簽名
          getSign(params, key){
            let string = this.raw(params) + '&key=' + key;
            let sign = createHash('md5').update(string).digest('hex');
            return sign.toUpperCase();
          },
          // 生成系統的交易訂單號
          getTradeId(type='wx'){
            let date = new Date().getTime().toString();
            let text = '';
            let possible = '0123456789';
            for(let i=0;i<5;i++){
              text += possible.charAt(Math.floor(Math.random() * possible.length))
            }
            return (type == 'wx'?'ImoocWxJuZi':'ImoocMpJuZi') + date + text;
          },
          // Object 轉換成json并排序
          raw(args){
            let keys = Object.keys(args).sort();
            let obj = {};
            keys.forEach((key)=>{
              obj[key] = args[key];
            })
            // {a:1,b:2} =>  &a=1&b=2
            // 將對象轉換為&分割的參數
            let val = '';
            for(let k in obj){
              val += '&' + k + '=' +obj[k];
            }
            return val.substr(1);
          }
        }復制代碼

        下面是對支付的方法的封裝,其中調用了util中的函數??蛻舳苏{用的就是下面的 order 方法。

        /**
         * 微信小程序、H5通用支付封裝
         */
        let config = require('./../pay/config')
        let request = require('request')
        let util = require('../../util/util')
        let createHash = require('create-hash')
        let xml = require('xml2js')
        config = config.mch;
        module.exports = {  
          order: function (appid,attach, body, openid, total_fee, notify_url, ip){
            return new Promise((resolve,reject)=>{
              let nonce_str = util.createNonceStr();
              let out_trade_no = util.getTradeId('mp');
              // 支付前需要先獲取支付簽名
              let sign = this.getPrePaySign(appid, attach, body, openid, total_fee, notify_url, ip, nonce_str, out_trade_no);
              // 通過參數和簽名組裝xml數據,用以調用統一下單接口
              let sendData = this.wxSendData(appid, attach, body, openid, total_fee, notify_url, ip, nonce_str, out_trade_no, sign);
              let self = this;
              let url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
              request({
                url,
                method: 'POST',
                body: sendData
              }, function (err, response, body) {
                if (!err && response.statusCode == 200) {
                  xml.parseString(body.toString('utf-8'),(error,res)=>{
                    if(!error){
                      let data = res.xml;
                      console.log('data:' + JSON.stringify(data));
                      if (data.return_code[0] == 'SUCCESS' && data.result_code[0] == 'SUCCESS'){
                        // 獲取預支付的ID
                        let prepay_id = data.prepay_id || [];
                        let payResult = self.getPayParams(appid, prepay_id[0]);
                        resolve(payResult);
                      }
                    }
                  })
                } else {
                  resolve(util.handleFail(err));
                }
              })
            })
          },
          // 生成預支付的簽名
          getPrePaySign: function (appid, attach, body, openid, total_fee, notify_url, ip, nonce_str, out_trade_no) {
            let params = {
              appid,
              attach,
              body,
              mch_id: config.mch_id,
              nonce_str,
              notify_url,
              openid,
              out_trade_no,
              spbill_create_ip: ip,
              total_fee,
              trade_type: 'JSAPI'
            }
            let string = util.raw(params) + '&key=' + config.key;
            let sign = createHash('md5').update(string).digest('hex');
            return sign.toUpperCase();
          },
          // 簽名成功后 ,根據參數拼接組裝XML格式的數據,調用下單接口
          wxSendData: function (appid, attach, body, openid, total_fee, notify_url, ip, nonce_str, out_trade_no,sign) {
            let data = '<xml>' + 
              '<appid><![CDATA[' + appid + ']]></appid>' + 
              '<attach><![CDATA[' + attach + ']]></attach>' + 
              '<body><![CDATA[' + body + ']]></body>' + 
              '<mch_id><![CDATA[' + config.mch_id + ']]></mch_id>' + 
              '<nonce_str><![CDATA[' + nonce_str + ']]></nonce_str>' + 
              '<notify_url><![CDATA[' + notify_url + ']]></notify_url>' + 
              '<openid><![CDATA[' + openid + ']]></openid>' + 
              '<out_trade_no><![CDATA[' + out_trade_no + ']]></out_trade_no>' + 
              '<spbill_create_ip><![CDATA[' + ip + ']]></spbill_create_ip>' + 
              '<total_fee><![CDATA[' + total_fee + ']]></total_fee>' + 
              '<trade_type><![CDATA[JSAPI]]></trade_type>' + 
              '<sign><![CDATA['+sign+']]></sign>' + 
            '</xml>'
            return data;
          },
          getPayParams:function(appId,prepay_id){
            let params = {
              appId,
              timeStamp:util.createTimeStamp(),
              nonceStr:util.createNonceStr(),
              package: 'prepay_id=' + prepay_id,
              signType:'MD5'
            }
            let paySign = util.getSign(params,config.key);
            params.paySign = paySign;
            return params;
          }
        }復制代碼

        最后定義 /pay/payWallet 的支付接口,里面調用公用的order方法。

        // 小程序支付
        router.get('/pay/payWallet',function(req,res){
          let openId = req.query.openId;//用戶的openid
          let appId = config.appId;//應用的ID
          let attach = "小程序支付課程體驗";//附加數據
          let body = "歡迎學習慕課首門支付專項課程";//支付主體內容
          let total_fee = req.query.money;//支付總金額
          let notify_url = "http://localhost:3000/api/mp/pay/callback"
          let ip = "123.57.2.144";
          wxpay.order(appId,attach,body,openId,total_fee,notify_url,ip).then((result)=>{
            res.json(util.handleSuc(result));
          }).catch((result)=>{
            res.json(util.handleFail(result.toString()))
          });
        })復制代碼

        這里的流程請參見 官方描述 。官方描述的非常清楚,這兒就不描述更多了,其實主要就是拼接一些參數,獲取 簽名 。然后根據簽名加上其他需要的 參數 (參見上述代碼)再憑借xml的數據。然后再調用統一下單接口 https://api.mch.weixin.qq.com/pay/unifiedorder 。生成 prepay_id之后,生成小程序端需要的一些參數,然后把這些參數返回個小程序客戶端,供小程序的客戶端調用微信小程序的支付功能。

        小程序前端支付非常簡單,只是簡單的調用服務端提供的 payWallet 接口,傳入 openId 和 money 即可。然后獲取到相應的參數,調用微信提供的 requestPayment 拉起支付即可。

        主要代碼邏輯如下:

        pay() {
            app.get(Api.payWallet,{
              openId: Store.getItem('openId'),
              money: this.data.index
            }).then((res) => {
              // 支付
              wx.requestPayment({
                timeStamp: res.timeStamp,
                nonceStr: res.nonceStr,
                package: res.package,
                signType: res.signType,
                paySign: res.paySign,
                success: function (errmsg) {
                  if (errmsg == 'requestPayment:ok') {
                    wx.showToast({
                      title: '支付成功',
                      icon: 'success'
                    });
                  }
                },
                fail: function (res) {
                  if (res.errMsg == 'requestPayment:fail cancel') {
                    wx.showToast({
                      title: '支付取消',
                      icon: 'none'
                    });
                  } else {
                    wx.showToast({
                      title: res.errmsg,
                      icon: 'none'
                    });
                  }
                }
              })
            });
          }
        復制代碼

        到這里,小程序端的支付功能就已經實現了。


        波多野吉不卡中文Av无码Av

          <strong id="fzzds"><track id="fzzds"></track></strong>
        1. <strong id="fzzds"></strong>
          <strong id="fzzds"></strong>
        2. <ruby id="fzzds"><bdo id="fzzds"><rp id="fzzds"></rp></bdo></ruby>
            <strike id="fzzds"></strike>