微信小程序后端实现授权登录
登录与授权
官方文档
一.登录登录流程时序
说明:
调用
- wx.login()获取临时登录凭证code,并回传到开发者服务器。
- 调用code2Session接口,换取用户唯一标识OpenID和会话密钥session_key。
之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。
注意:
会话密钥session_key是对用户数据进行加密签名的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。
临时登录凭证code只能使用一次
总结:
小程序端执行wx.login后在回调函数中就能拿到上图的code,然后把这个code传给我们后端程序,后端拿到这个这个code后,可以请求code2Session接口拿到用的openid和session_key,openid是用户在微信中唯一标识,我们就可以把这个两个值(val)存起来,然后返回一个键(key)给小程序端,下次小程序请求我们后端的时候,带上这个key,我们就能找到这个val,就可以,这样就把登入做好了。
wx.login
调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户的唯一标识(openid)及本次登录的会话
密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成。[/code]
参数
| 属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
|---|---|---|---|---|---|
| timeout | number | 否 | 超时时间,单位ms | 1.9.90 | |
| success | function | 否 | 接口调用成功的回调函数 | ||
| fail | function | 否 | 接口调用失败的回调函数 | ||
| complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
object.success回调函数
参数
属性
类型
说明
code
string
用户登录凭证(有效期五分钟)。开发者需要在开发者服务器后台调用 code2Session,使用code换取openid和session_key等信息
code2Session
本接口应在服务器端调用,详细说明参见服务端API。
登录凭证校验。通过wx.login()接口获得临时登录凭证code后传到开发者服务器调用此接口完成登录流程。更多使用方法详见小程序登录。
请求地址
GEThttps://api.weixin.qq.com/sns/jscode2sessionappid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
请求参数
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
| appid | string | 是 | 小程序appId | |
| secret | string | 是 | 小程序appSecret | |
| js_code | string | 是 | 登录时获取的code | |
| grant_type | string | 是 | 授权类型,此处只需填写authorization_code |
返回值
Object
返回的JSON数据包
| 属性 | 类型 | 说明 |
|---|---|---|
| openid | string | 用户唯一标识 |
| session_key | string | 会话密钥 |
| unionid | string | 用户在开放平台的唯一标识符,在满足UnionID下发条件的情况下会返回,详见 UnionID机制说明。 |
| errcode | number | 错误码 |
| errmsg | string | 错误信息 |
errcode的合法值
| 值 | 说明 |
|---|---|
| -1 | 系统繁忙,此时请开发者稍候再试 |
| 0 | 请求成功 |
| 40029 | code无效 |
| 45011 | 频率限制,每个用户每分钟100次 |
二.信息授权wx.getUserInfo
获取用户信息。
参数
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
| withCredentials | boolean | 否 | 是否带上登录态信息。当withCredentials为true时,要求此前有调用过wx.login且登录态尚未过期,此时返回的数据会包含encryptedData,iv等敏感信息;当withCredentials为false时,不要求有登录态,返回的数据不包含encryptedData,iv等敏感信息。 | |
| lang | string | en | 否 | 显示用户信息的语言 |
| success | function | 否 | 接口调用成功的回调函数 | |
| fail | function | 否 | 接口调用失败的回调函数 | |
| complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
object.lang的合法值
| 值 | 说明 |
|---|---|
| en | 英文 |
| zh_CN | 简体中文 |
| zh_TW | 繁体中文 |
object.success回调函数
参数
| 属性 | 类型 | 说明 |
|---|---|---|
| userInfo | UserInfo | 用户信息对象,不包含openid等敏感信息 |
| rawData | string | 不包括敏感信息的原始数据字符串,用于计算签名 |
| signature | string | 使用sha1(rawData+sessionkey)得到字符串,用于校验用户信息,详见 用户数据的签名验证和加解密 |
| encryptedData | string | 包括敏感数据在内的完整用户信息的加密数据,详见 用户数据的签名验证和加解密 |
| iv | string | 加密算法的初始向量,详见 用户数据的签名验证和加解密 |
注意:
1.小程序端获取授权信息要用button按钮触发
2.小程序端需要将encryptedData,iv,login_key传到后端用于解密
案例:
登录:
当小程序第一次执行的时候就调用wx.login
小程序端:apps.js
App({
onLaunch:function(){
var_this=this
//登录
wx.login({
success:res=>{
//发送res.code到后台换取openId,sessionKey,unionId
wx.request({
url:_this.globalData.Url+'/login/',//后端路径
data:{"code":res.code},//code
header:{"content-type":"application/json"},
method:"POST",
success:function(res){
console.log(res)
//小程序端存储login_key
wx.setStorageSync("login_key",res.data.data.login_key)
}
})
}
})
},
globalData:{
Url:"http://127.0.0.1:8000",
userInfo:null
}
})
后端django
wx ├──settings.py#小程序id,code2Session等配置 ├──wx_login.py#用于调用code2Session拿到openid等 └──WXBizDataCrypt.py#获取用户授权信息的解密算法,官方下载
微信官方解密算法代码
项目/settings.py
#配置数据库
DATABASES={
'default':{
'ENGINE':'django.db.backends.mysql',
'NAME':'wx',
'USER':'root',
'PASSWORD':'root',
'HOST':'127.0.0.1',
'PORT':3306,
'OPTIONS':{'charset':'utf8mb4'},#微信用户名可能有标签,所以用utf8mb4
}
}
#配置django-redis
CACHES={
'default':{
'BACKEND':'django_redis.cache.RedisCache',
'LOCATION':'redis://127.0.0.1:6379',
"OPTIONS":{
"CLIENT_CLASS":"django_redis.client.DefaultClient",
"PASSWORD":"",
},
},
}
wx/settings.py
#小程序开发者id
AppId="..."
#小程序的AppSecret
AppSecret="..."
code2Session="https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code"
pay_mchid='...'
pay_apikey='...'
wx/wx_login.py
fromapp01.wximportsettings
importrequests
#调用微信code2Session接口,换取用户唯一标识OpenID和会话密钥session_key
deflogin(code):
response=requests.get(settings.code2Session.format(settings.AppId,settings.AppSecret,code))
data=response.json()
ifdata.get("openid"):
returndata
else:
returnFalse
项目/views.py
fromrest_framework.viewsimportAPIView
fromrest_framework.responseimportResponse
fromapp01.wximportwx_login
fromdjango.core.cacheimportcache
fromapp01importmodels
importtime,hashlib
classLogin(APIView):
defpost(self,request):
param=request.data
#拿到小程序端提交的code
ifparam.get('code'):
#调用微信code2Session接口,换取用户唯一标识OpenID和会话密钥session_key
data=wx_login.login(param.get('code'))
ifdata:
#将openid和session_key拼接
val=data['openid']+"&"+data["session_key"]
key=data["openid"]+str(int(time.time()))
#将openid加密
md5=hashlib.md5()
md5.update(key.encode("utf-8"))
key=md5.hexdigest()
#保存到redis内存库,因为小程序端后续需要认证的操作会需要频繁校验
cache.set(key,val)
has_user=models.Wxuser.objects.filter(openid=data['openid']).first()
#用户不存在则创建用户
ifnothas_user:
models.Wxuser.objects.create(openid=data['openid'])
returnResponse({
"code":200,
"msg":"ok",
"data":{"login_key":key}#返回给小程序端
})
else:
returnResponse({"code":401,"msg":"code无效"})
else:
returnResponse({"code":401,"msg":"缺少参数"})
用户信息授权
小程序端test.wxml
授权登录
test.js
Page({
info:function(res){
//console.log(res)
wx.checkSession({
success(){
//session_key未过期,并且在本生命周期一直有效
wx.getUserInfo({
success:function(res){
//console.log(res)
wx.request({
url:app.globalData.Url+"/getinfo/",
data:{"encryptedData":res.encryptedData,"iv":res.iv,"login_key":wx.getStorageSync("login_key")},
method:"POST",
header:{"content-type":"application/json"},
success:function(res){
console.log(res)
}
})
}
})
})
后端django
wx/WXBizDataCrypt.py
importbase64
importjson
fromCrypto.CipherimportAES
fromapp01.wximportsettings
classWXBizDataCrypt:
def__init__(self,appId,sessionKey):
self.appId=appId
self.sessionKey=sessionKey
defdecrypt(self,encryptedData,iv):
#base64decode
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)))
ifdecrypted['watermark']['appid']!=self.appId:
raiseException('InvalidBuffer')
returndecrypted
def_unpad(self,s):
returns[:-ord(s[len(s)-1:])]
@classmethod
defgetInfo(cls,encryptedData,iv,session_key):
returncls(settings.AppId,session_key).decrypt(encryptedData,iv)
项目/serializer.py
fromrest_framework.serializersimportModelSerializer fromapp01importmodels classUser_ser(ModelSerializer): classMeta: model=models.Wxuser fields="__all__"
项目/views.py
fromapp01.wximportWXBizDataCrypt
fromapp01importserializer
fromapp01importmodels
classGetInfo(APIView):
defpost(self,request):
param=request.data
#需要小程序端将encryptedDataivlogin_key的值传到后端
#encryptedDataivseesion_key用于解密获取用户信息
#login_key用于校验用户登录状态
ifparam['encryptedData']andparam['iv']andparam['login_key']:
#从redis中拿到login_key并切分拿到openid和session_key
openid,seesion_key=cache.get(param['login_key']).split("&")
#利用微信官方提供算法拿到用户的开放数据
data=WXBizDataCrypt.WXBizDataCrypt.getInfo(param['encryptedData'],param['iv'],seesion_key)
save_data={
"name":data['nickName'],
"avatar":data['avatarUrl'],
"language":data['language'],
"province":data['province'],
"city":data['city'],
"country":data['country'],
}
#将拿到的用户信息更新到用户表中
models.Wxuser.objects.filter(openid=openid).update(**save_data)
#反序列化用户对象,并返回到小程序端
data=models.Wxuser.objects.filter(openid=openid).first()
data=serializer.User_ser(instance=data,many=False).data
returnResponse({"code":200,"msg":"缺少参数","data":data})
else:
returnResponse({"code":200,"msg":"缺少参数"})
到此这篇关于微信小程序后端实现授权登录的文章就介绍到这了,更多相关微信小程序授权登录内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。