• 一篇解决登录与支付


    1 登录篇

    1.1 微信登录

    1.1.1 微信小程序

    登录流程时序

    在这里插入图片描述
    说明

    1.调用wx.login()获取 临时登录凭证code ,并回传到开发者服务器
    2.调用auth.code2Session接口,换取 用户唯一标识 OpenID 和 会话密钥 session_key
    之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。

    注意

    1.会话密钥 session_key 是对用户数据进行加密签名的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。

    2.临时登录凭证 code 只能使用一次

    const request = require('/api/index.js');
    
    • 1
        login() {
            const that = this;
            return new Promise((resolve, reject) => {
                wx.checkSession({
                    success() {
                        // session_key 未过期,并且在本生命周期一直有效;
                        resolve();
                    },
                    fail() {
                        // session_key 已经失效,需要重新执行登录流程
                        wx.login({
                            success: res => {
                                // 发送res.code到后台换取openId,sessionKey,unionId
                                request.post('/user/login', {
                                    code: res.code
                                }).then(res => {
                                    let token = res.data.token;
                                    wx.setStorageSync('token', token);
                                    resolve();
                                })
                            }
                        })
                    }
                })
            })
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    code:用户登录凭证(有效期五分钟)。开发者需要在开发者服务器后台调用auth.code2session,使用code换取openid和sessionkey等信息。

    1.1.2 微信公众号

    微信公众号采用的是oauth2的登录授权方式;
    简单来讲,就是

    1.1 用户用过微信确认登录之后,微信方会返回一个授权码code给回第三方(接入方),这个授权码 >是一次性的,且有效期时间比较短;
    1.2 第三方通过此code去调用微信接口获取token,token的有效期也比较短;
    1.3 通过token再去调用微信平台接口,获取微信个人信息(昵称,头像地址,openid,unionid,地区……)

    2.1 通过重新赋值location.href,并传入服务号的appId以及redirect_uri跳转微信授权链接

    2.2 经过用户同意获取code;这里redirect_uri授权的页面地址,里面的location.host必须要经过授权才行,否则官方不会承认这个地址,也就不会返回code。
    示例如下(具体配置参考官方文档)

    export const requestWxCode = () => {
        const REDIRECT_URI = [location.protocol, "//", location.host, location.pathname].join('')
        location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APP_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=snsapi_userinfo&state=ok#wechat_redirect`
    }
    
    • 1
    • 2
    • 3
    • 4

    3.授权回调域名过程:
    ①拿服务号的账号和密码登录微信管理后台,找到网页授权
    ② 填写授权回调域
    ③ 将MP_verify_NWxYqcEY0l6bdRam.txt下载下来上传至填写域名或路径指向的web服务器(或者虚拟主机)的目录;校验确保可以访问;
    ④注意第三步,对于首次使用的域名,服务器根目录下是没有的,所以即便你在本地放置了,依旧是访问不到的;所以要么自己放置后部署,要么找运维手动放置;当可以点击“保存”时,就说明回调域名授权成功

    具体登录逻辑

    • 4.1 先判断是否在微信应用内打开,只有在应用内打开,才能调用微信的授权链接;
    • 4.2 判断缓存中是否有有效token(token存在并且未过期),如果有则可直接去接口请求;
    • 4.3 如果token不存在或者存在但已过期,则需要重新判断code,看链接上是否存在code或者code是不是重复的(重复的意味着一定不可用了,因为code是一次性的)
    • 4.4 如果code不存在,则手动重定向路由,以调用微信的授权链接如下:
    location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APP_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=snsapi_userinfo&state=ok#wechat_redirect`
    
    • 1

    用户同意授权后,就会发现路由地址变成了https://h5.xxxx.com/lvy-pay?code=0014sGyh2lXvIC05NYvh2B3qyh24sGyY&state=ok,上面含有code,取到code,向服务器换取token,并将此token及过期时间存到缓存中,方便下次打开时直接调用;这时就可以放开去发接口请求了

    具体可参考
    微信公众平台开发——微信授权登录(OAuth2.0)
    微信开放平台

    1.2 支付宝登录

    1.2.1 支付宝小程序

    		//uniapp代码
    		// #ifdef MP-ALIPAY  
    				// 获取服务供应商
    				let self = this;
    				uni.getProvider({
    					service: 'oauth',
    					success: function(res) {
    						// console.log(res.provider) //['alipay']
    						self.provider = res.provider[0];
    						// 获取用户登录凭证code
    						uni.login({
    							provider: self.provider,
    							success: loginRes => {
    								console.log('01----authCode获取成功', loginRes.authCode)
    								// 获取用户基础信息 无需授权 不含code
    								uni.getUserInfo({
    									provider: self.provider,
    									success(infoRes) {
    										mypublicing(
    												"/auth/applet/login", {
    													// code: auth.authCode,
    													code: loginRes.authCode,
    													client: 'zfb'
    												})
    											.then(res => {
    												// 			"code换openId",
    												if (res.data.code == 200) {
    													self.zfb.openId =res.data.data.openid;
    													console.log("02----openid获取成功",self.zfb)
    													if (res.data.data.access_token) {														           		      		    
    										uni.setStorageSync('token',red.data.data.access_token);
    													}
    												} else {
    													uni.showLoading({
    														title: "code换openid失败",
    													});
    												}
    
    											})
    										
    									}
    								});
    							}
    						});
    					}
    				});
    				// #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    2 支付篇

    2.1 微信支付

    2.1.1 H5支付

    H5支付是指,前端在浏览器唤起微信app,支付成功后再回到浏览器。

    前端发起请求,需要后台server 支持,请求微信支付服务,返回前端微信支付的链接。我们的回调地址,会以redirect_url 的形式拼的返回的链接后面,前端打开这个链接,就可以唤起微信支付。完成微信支付后,会回到回调地址。

    常见链接形如下面:

    MWEB_URL= wx.tenpay.com/cgi-bin/mmp…

    任务流程图
    在这里插入图片描述

    主要页面跳转:
    在这里插入图片描述
    泳道图在这里插入图片描述

    注意点

    1.当我们把h5页面嵌入到app内使用时,问题:ios 端在微信支付成功或者取消支付后,停留到了微信,无法回到app.会打开safari
    我们做了一个中转页面,专门供iOS 使用,在浏览器打开时,我们会以url schema 的形式唤起app,打开支付结果页面。

    2.注意微信xyRedirectUrl 编码后长度不可超过 800 微信支付会报错

    2.1.2 微信小程序支付

    小程序需要通过微信认证,开通微信支付能力。需要商户号资质,一般个人开发比较难搞
    调用方式比较JSAPI 较为简单,因为是在微信环境内,兼容性问题较少。

    appId: "wx5*5f7119*de*513"
    nonceStr: "JGIGiEuHY*nhyVvWpJcmeJ4W*Sa0VsdY"
    package: "prepay_id=wx2011*407469034*38132bda7cdc6690000"
    paySign: "A9A3AF*8197CF11A077*DD226566AAFB"
    signType: "MD5"
    timeStamp: "1658287447"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    //使用支付前需先引入微信SDK,否则无法调用成功
    //1.普通html,可以引入 
    //2.npm 包模块。引入 weixin-js-sdk 包
    
    		wx.config({
    		debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    		appId: '', // 必填,公众号的唯一标识
    		timestamp: , // 必填,生成签名的时间戳
    		nonceStr: '', // 必填,生成签名的随机串
    		signature: '',// 必填,签名
    		jsApiList: [
    		    'updateAppMessageShareData',
    		        'updateTimelineShareData',
    		        'onMenuShareWeibo',
    		        'onMenuShareQZone',
    		        'startRecord',
    		        'stopRecord',
    		        'onVoiceRecordEnd',
    		        'playVoice',
    		        'pauseVoice',
    		        'stopVoice',
    		        'onVoicePlayEnd',
    		        'uploadVoice',
    		        'downloadVoice',
    		        'chooseImage',
    		        'previewImage',
    		        'uploadImage',
    		        'downloadImage',
    		        'translateVoice',
    		        'getNetworkType',
    		        'openLocation',
    		        'getLocation',
    		        'hideOptionMenu',
    		        'showOptionMenu',
    		        'hideMenuItems',
    		        'showMenuItems',
    		        'hideAllNonBaseMenuItem',
    		        'showAllNonBaseMenuItem',
    		        'closeWindow',
    		        'scanQRCode',
    		        'chooseWXPay',
    		        'openProductSpecificView',
    		        'addCard',
    		        'chooseCard',
    		    ] // 必填,需要使用的JS接口列表
    		  },
    		  wx.error(function(res){
    		    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
    		  });
    		);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    	// #ifdef MP-WEIXIN
    wx.requestPayment({ 
        "timeStamp":"",// 时间戳,
        "nonceStr": "",//随机字符串,长度为32个字符以下。 
        "package": "",//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=* 
        "signType": ,
        "MD5",//签名方式,
        "paySign": "",//签名 
        "success":function(res){}, 
        "fail":function(res){}, 
        "complete":function(res){} 
    })
    	// #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.2 支付宝支付

    支付宝支付

    2.2.1 H5支付

    任务流程图
    请添加图片描述
    主要页面跳转:
    请添加图片描述

    代码:

    // 后台接口返回来的是form标签字符串 
    let _str = ` 
    <form id='alipaysubmit' name='alipaysubmit' action='https://openapi.alipay.com/gateway.do' method='POST'> 
    <input type='hidden' name='app_id' value='201805106……'/> 
    <input type='hidden' name='method' value='alipay.trade.page.pay'/> 
    <input type='hidden' name='format' value='JSON'/> 
    <input type='submit' value='ok' style='display:none;''> 
    form> <script>document.forms['alipaysubmit'].submit();script>`; 
    
    
    _str = _str.replace(/form/, 'form target="_blank"'); 
    div.innerHTML=_str; document.body.appendChild(div); document.forms.alipaysubmit.submit();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    1.直接调用后台的支付接口
    const params = {}
    alipay(params).then(res => {
        const { data } = res
        if (!data.alipay_trade_wap_pay_response) {
            document.querySelector('body').innerHtml = res.data;
            document.forms[0].submit()
        } else {
            console.log('支付宝支付失败')Toast(data.alipay_trade_wap_pay_response.msg)
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.2.2 APP支付

    2.2.3 支付宝小程序支付

    trade_no: "2022072022001495141459520641"
    
    • 1
    // #ifdef MP-ALIPAY
    uni.requestPayment({
    		provider: 'alipay',
    				orderInfo: trade_no, // ==tradeNO						
    				success: function(res) {},
    				fail: function(err) {},
    				complete:function(res){} 
    							})
    // #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    基于html+css+javascript+jquery+bootstarp响应式网页设计——大理我的家乡旅游景点
    裸机与RTOS(概念、关系、区别)
    使用Elasticsearch Python SDK 查询EasySearch
    【网络流】总结
    云原生周刊:Score 成为 CNCF 沙箱项目|2024.7.15
    重磅发布!RflySim Cloud 智能算法云仿真平台亮相,助力大规模集群算法高效训练
    React报错之Property ‘value‘ does not exist on type ‘HTMLElement‘
    MySQL系列-高级-性能分析工具-EXPLAIN
    QT day3
    最终前端后端小程序还有nginx配置
  • 原文地址:https://blog.csdn.net/qq_42244911/article/details/125885574