微信小程序后端实现授权登录


Posted in Javascript onFebruary 24, 2020

登录与授权

官方文档

一.登录登录流程时序

微信小程序后端实现授权登录

说明:

调用

  1. wx.login()获取临时登录凭证code,并回传到开发者服务器。
  2. 调用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 后传到开发者服务器调用此接口完成登录流程。更多使用方法详见小程序登录。

请求地址

GET https://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

from app01.wx import settings
import requests

# 调用微信code2Session接口,换取用户唯一标识 OpenID 和 会话密钥 session_key
def login(code):
 response = requests.get(settings.code2Session.format(settings.AppId,settings.AppSecret,code))
 data = response.json()
 if data.get("openid"):
  return data
 else:
  return False

项目/views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from app01.wx import wx_login
from django.core.cache import cache
from app01 import models
import time, hashlib

class Login(APIView):
 def post(self, request):
  param = request.data
  # 拿到小程序端提交的code
  if param.get('code'):
   # 调用微信code2Session接口,换取用户唯一标识 OpenID 和 会话密钥 session_key
   data = wx_login.login(param.get('code'))
   if data:
    # 将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()
    # 用户不存在则创建用户
    if not has_user:
     models.Wxuser.objects.create(openid=data['openid'])
    return Response({
     "code": 200,
     "msg": "ok",
     "data": {"login_key": key} # 返回给小程序端
    })
   else:
    return Response({"code": 401, "msg": "code无效"})
  else:
   return Response({"code": 401, "msg": "缺少参数"})

用户信息授权

小程序端test.wxml

<!--用户信息授权-->
<button open-type="getUserInfo" bindgetuserinfo="info">授权登录</button>

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

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 getInfo(cls,encryptedData,iv,session_key):
  return cls(settings.AppId,session_key).decrypt(encryptedData, iv)

项目/serializer.py

from rest_framework.serializers import ModelSerializer

from app01 import models
class User_ser(ModelSerializer):
 class Meta:
  model=models.Wxuser
  fields="__all__"

项目/views.py

from app01.wx import WXBizDataCrypt
from app01 import serializer
from app01 import models

class GetInfo(APIView):
 def post(self,request):
  param=request.data
  # 需要小程序端将 encryptedData iv login_key 的值传到后端
  # encryptedData iv seesion_key 用于解密获取用户信息
  # login_key 用于校验用户登录状态
  if param['encryptedData'] and param['iv'] and param['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
   return Response({"code":200,"msg":"缺少参数","data":data})
  else:
   return Response({"code":200,"msg":"缺少参数"})

到此这篇关于微信小程序后端实现授权登录的文章就介绍到这了,更多相关微信小程序 授权登录内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
[原创]静态页面也可以实现预览 列表不同的显示方式
Oct 14 Javascript
JavaScript的9个陷阱及评点分析
May 16 Javascript
Mootools 1.2教程 Fx.Morph、Fx选项和Fx事件
Sep 15 Javascript
异步JavaScript编程中的Promise使用方法
Jul 28 Javascript
谈谈JavaScript异步函数发展历程
Sep 29 Javascript
JS对HTML表格进行增删改操作
Aug 22 Javascript
ReactNative Image组件使用详解
Aug 07 Javascript
使用JS代码实现俄罗斯方块游戏
Aug 03 Javascript
详解小程序如何避免多次点击,重复触发事件
Apr 08 Javascript
JS前端知识点总结之内置对象,日期对象和定时器相关操作
Jul 05 Javascript
微信小程序用户授权、位置授权及获取微信绑定手机号
Jul 18 Javascript
JS实现刷新网页后之前浏览位置保持不变示例详解
Aug 14 Javascript
Node使用Nodemailer发送邮件的方法实现
Feb 24 #Javascript
原生javascript实现类似vue的数据绑定功能示例【观察者模式】
Feb 24 #Javascript
Vue 技巧之控制父类的 slot
Feb 24 #Javascript
原生javascript的ajax请求及后台PHP响应操作示例
Feb 24 #Javascript
在 Vue 中编写 SVG 图标组件的方法
Feb 24 #Javascript
原生javascript中this几种常见用法总结
Feb 24 #Javascript
js实现坦克大战游戏
Feb 24 #Javascript
You might like
便携利器 — TECSUN PL-365简评
2021/03/02 无线电
很让人受教的 提高php代码质量36计
2012/09/05 PHP
php实现图片缩放功能类
2013/12/18 PHP
PHP实现的回溯算法示例
2017/08/15 PHP
window.js 主要包含了页面的一些操作
2009/12/23 Javascript
js字符串转换成xml对象并使用技巧解读
2013/04/18 Javascript
怎么判断js脚本加载完成
2014/02/28 Javascript
jquery禁止输入数字以外的字符的示例(纯数字验证码)
2014/04/10 Javascript
跟我学习javascript的最新标准ES6
2015/11/20 Javascript
jquery实现定时自动轮播特效
2015/12/10 Javascript
Javascript动画效果(1)
2016/10/11 Javascript
详解JavaScript树结构
2017/01/09 Javascript
jquery实现图片轮播器
2017/05/23 jQuery
js CSS3实现卡牌旋转切换效果
2017/07/04 Javascript
深入理解Vue 单向数据流的原理
2017/11/09 Javascript
vue监听键盘事件的快捷方法【推荐】
2018/07/11 Javascript
通过jquery的ajax请求本地的json文件方法
2018/08/08 jQuery
详解JavaScript 新语法之Class 的私有属性与私有方法
2019/04/23 Javascript
python&amp;MongoDB爬取图书馆借阅记录
2016/02/05 Python
基于python 字符编码的理解
2017/09/02 Python
python实现学生信息管理系统
2020/04/05 Python
利用Python写一个爬妹子的爬虫
2018/06/08 Python
Python3.5常见内置方法参数用法实例详解
2019/04/29 Python
Python图像处理PIL各模块详细介绍(推荐)
2019/07/17 Python
Pandas时间序列:重采样及频率转换方式
2019/12/26 Python
关于python的缩进规则的知识点详解
2020/06/22 Python
python 爬虫请求模块requests详解
2020/12/04 Python
Alba Moda德国网上商店:意大利时尚女装销售
2016/11/14 全球购物
小学生元旦广播稿
2014/02/21 职场文书
体育教学随笔感言
2014/02/24 职场文书
小班幼儿评语大全
2014/04/30 职场文书
八项规定对照检查材料
2014/08/31 职场文书
2014年财务工作总结范文
2014/11/11 职场文书
2016年教师新年寄语
2015/08/18 职场文书
求职自荐信该如何书写?
2019/06/24 职场文书
OpenCV-Python实现图像平滑处理操作
2021/06/08 Python