miniapp之登录、授权和支付
微信小程序代码实现(登录、授权和支付)
整体流程看上一篇博客,或者去微信公众平台查看文档
只列出核心代码,详细代码见码云michaelben
登录
// //小程序端
// app.js
App({
onLaunch: function () {
var that=this
// // 登录
wx.login({
success: res => {
console.log("code",res.code)
wx.request({
url: that.globalData.URL+"login/",
data:{
"code":res.code
},
header:{
"content-type":"application/json"
},
method:"POST",
success:function(e){
console.log(e)
wx.setStorageSync("token", e.data.data.token)
}
})
//发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
// onShow:function(e){
// // console.log("show",e)
// },
// onHide:function(){
// console.log("hide")
// },
// onError:function(e){
// console.log("error", e)
// },
globalData: {
userInfo: null,
URL:"http://127.0.0.1:8000/"
}
})
## 后端
# url.py
path('login/', views.Login.as_view()),
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.wx import Wx_login
import time, hashlib
from django.core.cache import cache
from app01 import models
class Login(APIView):
def post(self,request):
param = request.data
if param.get("code"):
# print(param.get('code'))
data=Wx_login.login(param.get("code"))
# print(data)
if data:
# 1 session_key+时间戳存到一个key.md5
md5=hashlib.md5()
md5.update(data.get("session_key").encode("utf8"))
md5.update(str(time.time()).encode("utf8"))
key=md5.hexdigest()
#2 session_key与openid做绑定赋值给val
val=data.get("session_key")+'&'+data.get("openid")
#3key->val存到redis,
cache.set(key,val)
#4把openid存到数据库
user_data=models.Wxuser.objects.filter(openid=data.get("openid")).first()
if not user_data:
models.Wxuser.objects.create(openid=data.get("openid"))
#5把key返回给小程序
return Response({"code": 200, "msg": "suc","data":{"token":key}})
else:
return Response({"code": 202, "msg": "code无效"})
else:
return Response({"code":201,"msg":"缺少参数"})
授权(只列出录音,其他非userinfo需要权限的功能见授权)
// test.wxml
<button bind:tap="record">录音</button>
//test.js
const app=getApp()
record:function(){
wx.getSetting({
success(res) {
console.log("res", res.authSetting['scope.record'])
if (!res.authSetting['scope.record']) {
wx.authorize({
scope: 'scope.record',
success() {
// 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问
wx.startRecord()
},
fail(){
console.log("你没有授权")
}
})
}else{
wx.startRecord()
}
}
})
}
授权(用户信息)
前端
// test.wxml
<button open-type="getUserInfo" bindgetuserinfo="info1">获取用户信息</button>
// test.js
info1:function(res){
console.log(res,"按钮")
// wx.getUserInfo({
// success: function (res) {
// console.log(res, "用户信息")
// }
// })
var that=this
wx.checkSession({
success() {
//session_key 未过期,并且在本生命周期一直有效
wx.request({
url: app.globalData.URL + "userinfo/",
data: {
encryptedData: res.detail.encryptedData,
iv: res.detail.iv,
token:wx.getStorageSync("token")
},
header: {
"content-type": "application/json"
},
method: "POST",
success: function (e) {
console.log(e)
}
})
},
fail() {
// session_key 已经失效,需要重新执行登录流程
// wx.login() //重新登录
}
})
},
后端
#view.py
class UserInfo(APIView):
def post(self,request):
param = request.data
if param.get('token') and param.get("encryptedData") and param.get("iv"):
cache_data=cache.get(param.get('token'))
print(cache_data)
if cache_data:
# 获取session_key
session_key,openid=cache_data.split("&")
#数据解密
user_info=WXBizDataCrypt.get_info(session_key, param.get("encryptedData"),param.get("iv"))
print(user_info)
#存入数据库
user_data={
'name': user_info['nickName'],
'avatar': user_info['avatarUrl'],
'language': user_info['language'],
'province': user_info['province'],
'city': user_info['city'],
'country': user_info['country'],
}
models.Wxuser.objects.filter(openid=openid).update(**user_data)
data=models.Wxuser.objects.filter(openid=openid).first()
data=Wxuser_ser.Wxuser_ser(data,many=False).data
return Response({"code": 200, "msg": "suc", "data": data})
else:
return Response({"code": 202, "msg": "token无效"})
else:
return Response({"code": 201, "msg": "缺少参数"})
#WXBiz.py
import base64
import json
from Crypto.Cipher import AES
from app01.wx import settings
class WXBizDataCrypt:
def __init__(self, appId, sessionKey):
self.appId = appId
self.sessionKey = sessionKey
def decrypt(self, encryptedData, iv):
# base64 decode
sessionKey = base64.b64decode(self.sessionKey)
encryptedData = base64.b64decode(encryptedData)
iv = base64.b64decode(iv)
cipher = AES.new(sessionKey, AES.MODE_CBC, iv)
decrypted = json.loads(self._unpad(cipher.decrypt(encryptedData)))
if decrypted['watermark']['appid'] != self.appId:
raise Exception('Invalid Buffer')
return decrypted
def _unpad(self, s):
return s[:-ord(s[len(s)-1:])]
@classmethod
def get_info(cls,sessionKey,encryptedData,iv):
return cls(settings.AppId, sessionKey).decrypt(encryptedData, iv)
支付(详细见码云和官方文档)
后端
class Pay(APIView):
def post(self,request):
param = request.data
if param.get("token"):
cache_data = cache.get(param.get("token"))
if cache_data:
# 获取客户端ip,如果是负载均衡,就用HTTP_X_FORWARDED_FOR,如果不是就用下面的
if request.META.get('HTTP_X_FORWARDED_FOR'):
self.ip = request.META['HTTP_X_FORWARDED_FOR']
else:
self.ip = request.META['REMOTE_ADDR']
session_key,self.openid=cache_data.split("&")
data=self.get_pay_data()
return Response({"code": 200, "msg": "suc","data":data})
else:
return Response({"code": 202, "msg": "token无效"})
def get_nonce_str(self,num=30):
# strs = ""
# for i in range(30):
# strs += str(random.randint(0,9))
all_str = "0123456789abcdefghijklmnopqrstuvwxyz"
strs = "".join(random.sample(all_str,num))
return strs
def get_out_trade_no(self):
import time
strs = str(int(time.time()))+self.get_nonce_str(5)
return strs
def get_sign(self):
data_dic = {
"nonce_str": self.nonce_str,
"out_trade_no": self.out_trade_no,
"spbill_create_ip": self.ip,
"notify_url": self.notify_url,
"openid": self.openid,
"body": self.body,
"trade_type": "JSAPI",
"sign_type": "MD5",
"appid": self.appid,
"total_fee": self.total_fee,
"mch_id": self.mch_id
}
str_a = "&".join([ f"{i}={data_dic[i]}" for i in sorted(data_dic)])
str_b = f"{str_a}&key={settings.pay_apikey}"
md5 = hashlib.md5()
md5.update(str_b.encode("utf8"))
return md5.hexdigest().upper()
def xml_to_dic(self,xml_data):
import xml.etree.ElementTree as ET
xml_data = ET.fromstring(xml_data)
dic = {}
for child in xml_data:
dic[child.tag] =child.text
return dic
def get_prepay_data(self):
url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
response = requests.post(url=url,data=self.body_data.encode("utf8"),headers={"content-type":"application/xml"})
xml_data = response.content
dic_data = self.xml_to_dic(xml_data)
return dic_data
def get_second_sign(self):
self.second_nonceStr = self.get_nonce_str()
self.timeStamp = str(int(time.time()))
data_dic = {
"appId":settings.AppId,
"timeStamp":self.timeStamp,
"nonceStr":self.second_nonceStr,
"package":f"prepay_id={self.prepay_data.get('prepay_id')}",
"signType":"MD5"
}
print(data_dic)
str_a = "&".join([f"{i}={data_dic[i]}" for i in sorted(data_dic)])
str_b = f"{str_a}&key={settings.pay_apikey}"
md5 = hashlib.md5()
md5.update(str_b.encode("utf8"))
return md5.hexdigest().upper()
def get_pay_data(self):
self.appid = settings.AppId
self.mch_id = settings.pay_mchid
self.nonce_str = self.get_nonce_str()
self.sign_type = "MD5"
self.body = "py11最难一届"
self.out_trade_no = self.get_out_trade_no()
self.total_fee = 1
self.spbill_create_ip = self.ip
self.notify_url = "http://www.weixin.qq.com/wxpay/pay.php"
self.trade_type = "JSAPI"
self.sign = self.get_sign()
self.body_data = f"""
<xml>
<appid>{self.appid}</appid>
<mch_id>{self.mch_id}</mch_id>
<nonce_str>{self.nonce_str}</nonce_str>
<sign>{self.sign}</sign>
<body>{self.body}</body>
<out_trade_no>{self.out_trade_no}</out_trade_no>
<total_fee>1</total_fee>
<sign_type>MD5</sign_type>
<spbill_create_ip>{ self.spbill_create_ip}</spbill_create_ip>
<notify_url>{self.notify_url}</notify_url>
<openid>{self.openid}</openid>
<trade_type>JSAPI</trade_type>
</xml>"""
self.prepay_data=self.get_prepay_data()
second_sign=self.get_second_sign()
data = {
"timeStamp":self.timeStamp,
"nonceStr":self.second_nonceStr,
"package":f"prepay_id={self.prepay_data.get('prepay_id')}",
"paySign":second_sign
}
return data
miniapp之登录、授权和支付的更多相关文章
- 微信小程序之结构目录、视图层、双线程模型、生命周期、事件传递冒泡、组件、request、登录授权及支付
结构目录与配置介绍 视图层与基础语法 双线程模型 生命周期 事件.传递和冒泡 组件.自定义组件.组件事件传递页面 Request.路由跳转.本地存储 登录(后端实现) | 授权(后端实现) 支付(后端 ...
- Vue/小程序/小程序云+Node+Mongo开发微信授权、支付和分享
大家好,我是河畔一角,今天给大家介绍我的第三门实战课程:基于微信开发的H5.小程序和小程序云的授权.支付和分享专项课程. 一.这一次为什么会选择微信支付和分享的课题呢? 金庸的小说中曾提到:有人的地方 ...
- 混合应用 微信登录授权 微信登录认证失败 ios PGWXAPI错误-1 code:-100 / 安卓 message:invalid appsecret innerCode:40125
最近项目需要做微信登录,于是利用HTML5+ API Reference的OAuth模块管理客户端的用户登录授权验证功能,允许应用访问第三方平台的资源.(链接:https://www.dcloud.i ...
- 网站微信登录授权 ASP.NET
最新做一些项目都有微信登录注册什么的,今天就把自己整理的demo提供给大家 微信认证流程(我自己简称三次握手): 1.用户同意授权,获取code 2.通过code换取网页授权access_token, ...
- MVC 自定义过滤器/特性来实现登录授权及验证
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 最近在做自学MVC,遇到的问题很多,索性一点点总结 ...
- Amazon Alexa登录授权(Android)
访问Alexa的API,必须要携带AccessToken,也就是必须要登录授权,本文主要记录Amazon Alexa在Android平台上的登录授权过程. 一.在亚马逊开发者平台注册应用 进入亚马逊开 ...
- Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员、后台管理员同时登录
1.登录的实现 登录功能实现起来有哪些常用的方式,大家首先想到的肯定是cookie或session或cookie+session,当然还有其他模式,今天主要探讨一下在Asp.net core 2.0下 ...
- 06_NoSQL数据库之Redis数据库:Redis的高级应用之登录授权和主从复制
Redis高级实用特征 安全性(登录授权和登录后使用auth授权) 设置客户端连接后进行任何其他指定前需要使用的密码. 警告:因为redis速度相当快,所以在一台比较好的服务器下,一个外部的用户 ...
- 关于微信登录授权获取unionid的方法
前言:微信登录授权是目前普遍存在于小程序的,还有一种静默授权方式是微信提供的但是不推荐使用,由于不同设备登录openid是不同的那么我们应该怎样拿到一个唯一的ID呢,下面做分享 wxml代码 < ...
随机推荐
- STL pair类型的介绍
pair标准库类型它定义在头文件utility中. 一个pair保存两个数据成员.类似容器,pair是一个用来生成特定类型的模板.当创建一个pair时,我们必须提供两个类型名,pair的数据成员将具有 ...
- javascript中的闭包、函数的toString方法
闭包: 闭包可以理解为定义在一个函数内部的函数, 函数A内部定义了函数B, 函数B有访问函数A内部变量的权力: 闭包是函数和子函数之间的桥梁: 举个例子: let func = function() ...
- electron窗口间通信
以下代码均来自于我开发的开源软件:想学吗 窗口A的渲染进程发消息给主进程 const { clipboard, ipcRenderer, remote } = require('electron'); ...
- HTML连载49-清除浮动的第三种方式(内外墙法)
一.清除浮动的第三种方式 1.隔墙法有两种如下:外墙法和内墙法. 2.外墙法 (1)在两个盒子中间添加一个额外的块级元素 (2)给这个额外添加的块级元素设置:clear:both;属性 注意点: ...
- 分析FAT32内部结构-入门篇-
FAT32(File Allocation Table)是一种32位的FAT文件系统,微软在1996年8月发布. FAT32的数字32是下面会讲到的FAT中每个表项的长度. 磁盘(硬盘)是数据的载体, ...
- 【Linux命令】id,usermod用户管理命令(包括/etc/passwd、shadow、group、gshadow文件)
一.id命令 可以用来查看用户的UID.GID和附加组信息 id会显示用户以及所属群组的实际与有效ID.若两个ID相同,则仅显示实际ID.若仅指定用户名称,则显示目前用户的ID. 1.格式 id [O ...
- 11-Django站点管理
站点管理 内容发布的部分由网站的管理员负责,包括查看.添加.修改.删除数据 开发这些重复的功能是一件单调乏味.缺乏创造力的工作,为此,Django能够根据定义的模型类自动地生成管理模块 在Django ...
- MyEclipse构建maven项目报错
直接上图: 这里有三种方案: 1.检查jdk版本:最好换成1.8版本 项目右键-->build path-->configure build Path; 1.2 点击 libraries ...
- WPF 使用动画设置特殊值的方法
例如设置Visibility属性时: 第一种方式: <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIEleme ...
- Spring Cloud Gateway-自定义异常处理
前提 我们平时在用SpringMVC的时候,只要是经过DispatcherServlet处理的请求,可以通过@ControllerAdvice和@ExceptionHandler自定义不同类型异常的处 ...