微信用户授权登入获取用户信息
需求:后端获取该用户的详情信息。保存至后台数据库,前端也要获取用户信息。
小程序端
1 必须保证用户是授权的,小程序端就可以获取非敏感信息,且要保证用户的后端保存的session_key是有效状态,将授权后的 iv,encryptedData,login_key传给后端。
app.josn
{ "pages": [ "pages/list/list", "pages/item/item", "pages/login/login" ], "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#e50e38", "navigationBarTitleText": "百步生活", "navigationBarTextStyle": "#fff", "enablePullDownRefresh": false, "backgroundColor": "#e50e38" }, }
app.js
App({ onLaunch: function () { // 展示本地存储能力001bHJ281qo7rS1JR1481OQC281bHJ2B var _this = this; wx.login({ success: res => { // console.log(res); wx.request({ url: _this.globalData.apiDomain +'/api/member/code/login', data: { code: res.code }, method: "POST", header: { 'content-type': 'application/json' // 默认值 }, success: function (res) { console.log(res); wx.setStorageSync('login_key', res.data.data.login_key); }, fail:function(res){ console.log(res) } }) } }); }, //设置全局的变量,apiDomain这是我们接口的ip globalData: { apiDomain:'http://127.0.0.1:8000', //保存当前用户的基本信息 userInfo: null, login_key:'' } })
login.wxml
<view class="container"> <image class="avatar" src="../../images/purplebox.jpg"></image> <view class="name">百步有礼</view> <view class="agree">请同意授权</view> <view class="author">·以便百步有礼为你提供更好的服务</view> <button open-type="getUserInfo" bindgetuserinfo="getUserInfo">登录</button> </view>
login.wxss
button{ margin-top:60rpx; width:590rpx; background:#51a938; color:#fff; } .container{ padding-top: 100rpx; } .avatar{ width:180rpx; height:180rpx; border-radius:50%; border:2rpx solid #eee; } .name{ padding-top:12rpx; font-size:36rpx; font-weight:bolder; } .agree{ margin-top:120rpx; text-align:left; width:670rpx; padding-left:80rpx; font-weight:bolder; font-size:30rpx; } .author{ line-height:90rpx; font-size:30rpx; width:670rpx; text-align:left; padding-left:80rpx; }
login.json
{ "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "授权登录", "navigationBarTextStyle": "black" }
login.js
//获取应用实例 const app = getApp(); Page({ data: { }, getUserInfo: function (e) { if(e.detail.userInfo){ var _this = this; app.globalData.userInfo = e.detail.userInfo this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }); wx.request({ url: app.globalData.apiDomain+'/api/member/code/getUserInfo', data: { 'iv': e.detail.iv, 'encryptedData': e.detail.encryptedData, 'login_key': wx.getStorageSync('login_key') }, method: "POST", header: { 'content-type': 'application/json' // 默认值 }, success: function (res) { wx.navigateBack({ delta: 1 }) } }); }; }, })
服务端
1接收 iv,encryptedData,login_key,通过login_key取出session_key和openid。通过调用微信接口,获取解密数据。
2 获取成功后,更新当前用户的详细信息,并可以将敏感信息传递给前端
url.py
from django.contrib import admin from django.urls import path from django.conf.urls import url from api.views import product,user urlpatterns = [ path('admin/', admin.site.urls), url(r'^api/indexlist/categoryList$', product.caetgoryList.as_view()), url(r'^api/indexlist/IndexProductList$', product.ProductList.as_view()), url(r'^api/indexlist/categoryProductsList$', product.categoryProductsList.as_view()), url(r'^api/indexlist/detailProduct$', product.detailProduct.as_view()), url(r'^api/member/code/login$', user.login.as_view()), url(r'^api/member/code/getUserInfo$', user.getUserInfo.as_view()), ]
user.py
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from api.wx import wxlogin,UserInfo,setting from api import baseResponse import time from django.core.cache import cache #引入缓存模块 from api import models from django.http import JsonResponse import hashlib # Create your views here. class login(APIView): def post(self,request): # 用apiview之后,再取数据,从request.data params=request.data #判断前端是否传入code参数 if params.get('code'): code=params['code'] #调用wxloing.getLoginInfo获取session_key和openid user_data=wxlogin.getLoginInfo(code) if user_data: #将session_key和openid拼接成字符串,不要乱选拼接字符串,因为openid中有特殊符号 val=user_data['session_key']+'&'+user_data['openid'] #生成MD5值获取key md=hashlib.md5() md.update(code.encode('utf-8')) md.update(str(time.clock()).encode('utf-8')) key = md.hexdigest() data={} try: #将key和上面的val存入redis cache.set(key,val) #返回login_key到小程序 data['login_key'] = key #将用户数据存入数据库 try: user = models.Wxuser.objects.get(openid=user_data['openid']) except Exception as e: user=None #如果数据没有则创建记录 if not user: models.Wxuser.objects.create(openid=user_data['openid']) re_data = baseResponse.resdic("success", "成功",data ) return JsonResponse(re_data) except Exception as e: print(e) re_data = baseResponse.resdic("error", "redis程序出错" ) return JsonResponse(re_data) else: re_data = baseResponse.resdic("error", "获取session_key失败") return JsonResponse(re_data) else: re_data = baseResponse.resdic("error", "缺少参数") return JsonResponse(re_data) class getUserInfo(APIView): def post(self,request): params = request.data #判断小程序是否传入这些参数 if params.get('encryptedData') and params.get('iv') and params.get('login_key'): encryptedData =params['encryptedData'] iv = params['iv'] login_key = params['login_key'] data=cache.get(login_key) #判断login_key是否过期 if not data: re_data = baseResponse.resdic("error", "login_key已过期") return JsonResponse(re_data) #将字符串分成列表 data_list=data.split('&') #pc = WXBizDataCrypt(appId, sessionKey) print(data_list) try: #调用 UserInfo.WXBizDataCrypt,obj.decrypt解密数据 use_class = UserInfo.WXBizDataCrypt(setting.AppId, data_list[0]) user_info=use_class.decrypt(encryptedData, iv) except Exception as e: re_data = baseResponse.resdic("error", "解密失败") return JsonResponse(re_data) #解密成功后组织存入数据库数据, save_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'], 'gender':user_info['gender'], } # models.Wxuser.objects.filter(openid=data_list[1]).update(name=user_info['nickName'], # avatar=user_info['avatarUrl'], # language=user_info['language'], # province=user_info['province'], # city=user_info['city'], # country=user_info['country'], # gender=user_info['gender']) #更新当前用户的数据 models.Wxuser.objects.filter(openid=data_list[1]).update(**save_data) #将解密后的数据返回小程序。 re_data = baseResponse.resdic("success", "成功",user_info) return JsonResponse(re_data) #解密获取用户信息 else: re_data = baseResponse.resdic("error", "缺少参数") return JsonResponse(re_data)
api.wx.UserInfo.py
import base64 import json from Crypto.Cipher import AES 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:])]