描述

假设的我们的服务号有这么一些功能,比如底部有按钮,点击会有一些复杂的功能,这时候可能就需要一个用户系统,有用户系统就经常想要做什么分享邀请新用户之类的,这时候就又有几种方式,1.直接一个连接,让其他用户点;2.有一个二维码,让离得近的朋友扫。

借着这个需求体会了下微信开发的两种不同类型(80非80端口的两种开发),以及python-social-auth的一些正确姿势。

而这个需求其实就对应了两种开发模式,比如有个需求可以在公众号内直接回复,或者在一个页面里面让用户提交表单等等。


通过连接邀请

首先,理解需求:用户在微信点击我们的邀请连接后,会引导用户做一个有绿色按钮的微信登录,用户登陆后成为我们的用户,并且跳转到某个页面。

关于用户微信登录的事情我们通过python-social-auth已经解决了(参考我的上一篇博客微信公众号开发小记——3.接入三方登录),所以可以直接用django的login_required装饰器完成这种事情。

由于微信号的登录只有微信,所以LOGIN_URL = '/login/weixinapp/'

class InviteUserView(View):'''邀请注册'''@method_decorator(login_required)def get(self, request):return HttpResponseRedirect(reverse('myauth:personal-center'))

上面的代码只是保证用户点解邀请链接会成为我们的用户,但是没有记录对应的邀请者信息等等,由于邀请这个事情其实是一个登录的流程,所以可以写在pipeline里面

def invite_user(backend, user, response, *args, **kwargs):is_new = kwargs['is_new']if not is_new or not user:return# 二维码扫描...# 点击邀请链接next_url = backend.strategy.session_get('next')if next_url:params = parse_url(next_url)['params']inviter_id = params.get('inviter_id')if inviter_id and user:try:inviter = User.objects.get(id=inviter_id)UserInvite.invite_user(inviter_id, user, only_allow_invited_by_one_user=True)except:returnuser._inviter = inviterreturn {'inviter': inviter}

通过扫码邀请

首先,扫码是一个服务号80端口的事件,所以代码添加在weixin_server/views.py 微信公众号开发小记——2.80端口上的服务

难点在于这里,微信扫码后是直接进入公众号的,如果你想要让用户进入公众号之后就变成我们的用户而不是让他在点一个东西这里是比较蛋疼的,因为你的服务器在这时候做302微信是不认得。这就导致了几个问题:

由于不引导用户登录,我这里没办法直接用python-social-auth里面的do_complete方法(因为拿不到用户的access_token),不过好处是使用微信服务器的access_token以及用户的openid我可以直接拿到这个用户的用户信息。这个问题就变成了python-social-auth的do_complete有用户response后执行pipeline的逻辑了。

然后我扒了下代码,用了几个小时从单测里面找到了这个逻辑,具体见handle_invite_scan这段代码才是这篇博客里面难度最大的东西

def weixin_handler_event_scan(self, request, parsed_wechat, *args, **kwargs):key = parsed_wechat.message.key # 对应生成二维码的keyticket = parsed_wechat.message.ticketif ticket:response = self.handle_invite_scan(request, parsed_wechat, key)if response:return responsereturn self.weixin_handler_event(request, parsed_wechat, *args, **kwargs)def handle_invite_scan(self, request, parsed_wechat, scene_id):try:qrcode = QRCode.objects.get(scene_id=scene_id, action_type='invite_user')except QRCode.DoesNotExist:returnopenid = parsed_wechat.message.sourceuser_info = parsed_wechat.get_user_info(openid)strategy = load_strategy(request)backend = WeixinOAuth2APP()backend.strategy = strategyidx, backend, xargs, xkwargs = strategy.partial_from_session({'next':0,'backend': backend,'args':[],'kwargs':{'qrcode': qrcode},})xkwargs.update({'response': user_info})user = backend.continue_pipeline(pipeline_index=idx, *xargs, **xkwargs)if not user:returnif user.is_new and hasattr(user, '_inviter'):content = u'感谢您的加入,邀请者是 {}'.format(user._inviter.username)response_xml = parsed_wechat.response_text(content=content)return HttpResponse(response_xml, content_type='application/xml')

然后就可以正常的执行了,由于二维码的机制跟url不同,所以需要单独的二维码处理逻辑

下面先把pipeline的那段代码贴过来,这里没什么特殊的

def invite_user(backend, user, response, *args, **kwargs):is_new = kwargs['is_new']if not is_new or not user:return# 二维码扫描qrcode = kwargs.get('qrcode')if qrcode and qrcode.userprofile_set.all().exists():inviter = qrcode.userprofile_set.all()[0].usertry:UserInvite.invite_user(inviter.id, user, only_allow_invited_by_one_user=True)except:returnuser._inviter = inviterreturn {'inviter': inviter}....

微信二维码

二维码有两种大的类型,永久二维码、临时二维码,永久上线10万张,scenen_id为1~10万,然而他又有scenen_str这种字符串的形式,那肯定选第二种字符串了;临时二维码则scenen_id为1~2^10,这点需要注意,超过这个限制secen_id都是2^10-1,而且蛋疼的是,临时二维码会有过期时间需要维护这个二维码。为了方便我们的业务逻辑查询,我添加了一个action_type的字段,来做业务上的区别,方便查询。

class QRCode(models.Model):TEMP_QRCODE_UPDATE_DAYS = 7QR_SCENE = 'QR_SCENE'QR_LIMIT_SCENE = 'QR_LIMIT_SCENE'QR_LIMIT_STR_SCENE = 'QR_LIMIT_STR_SCENE'ACTION_NAME_CHOICES = ((QR_SCENE, QR_SCENE),(QR_LIMIT_SCENE, QR_LIMIT_SCENE),(QR_LIMIT_STR_SCENE, QR_LIMIT_STR_SCENE),)url = models.URLField(blank=True, max_length=255, default='')# QR_SCENE时上限为2**32scene_id = models.CharField(blank=True, max_length=255, db_index=True, default='')update_time = models.DateTimeField(blank=True, null=True)action_name = models.CharField(max_length=30,choices=ACTION_NAME_CHOICES, default=QR_SCENE, db_index=True)action_type = models.CharField(max_length=255, default='', db_index=True)@classmethoddef get_qrcode(cls, action_name, scene_id, action_type=None):now = timezone.now()qrcode = Nonetry:qrcode = cls.objects.get(action_name=action_name, scene_id=scene_id)# 临时二维码判断是否过期if qrcode.action_name == cls.QR_SCENE:if qrcode.update_time and qrcode.url:_delta = now - qrcode.update_timeif _delta.days < qrcode.TEMP_QRCODE_UPDATE_DAYS:return qrcodeelse:return qrcodeexcept cls.DoesNotExist:passif not qrcode:qrcode = cls(action_name=action_name,scene_id=scene_id,action_type=action_type)qrcode.update_time = nowif action_name == cls.QR_SCENE:qrcode.url = create_temp_qrcode(scene_id)else:qrcode.url = create_permanent_qrcode(scene_id)qrcode.save()return qrcode@classmethoddef generate_temp_scene_id(cls, obj_id):'''max id: 2 ** 32 = 4294967296'''return int('{}{}{}'.format(randint(1, 3), obj_id, uuid4().int)[:9])@propertydef qrcode_url(self):if not self.action_name or not self.scene_id:raise Exception(u'qrcode object must have action_name and scene_id value')now = timezone.now()# 永久化的二维码不必更新if self.action_name != self.QR_SCENE:if not self.url:self.update_time = nowself.url = create_permanent_qrcode(self.scene_id)self.save()return self.url# 临时二维码判断是否过期if self.update_time and self.url:_delta = now - self.update_timeif _delta.days < self.TEMP_QRCODE_UPDATE_DAYS:return self.urlself.update_time = nowself.url = create_temp_qrcode(self.scene_id)self.save()return self.url

微信公众号开发小记——4.两种邀请用户的方式 扫码链接相关推荐

  1. 微信公众号开发小记(二)--服务器验证

    这篇是微信公众号开发小记的第二篇,承接上一篇,此次将完成如下主要功能 对接微信服务器和自己的服务器 需要的"材料" 到这里需要梳理一下都需要什么东西,以便在整个编码的过程中方便我们 ...

  2. 微信公众号开发之生成并扫描带参数的二维码(无需改动)

    首先把参考的博文罗列出来: 1.微信公众号开发之生成并扫描带参数的二维码: https://blog.csdn.net/qq_23543983/article/details/80228558 2.由 ...

  3. 急急急求微信公众号开发接口-php如何实现获取用户发送的微信表情,并返回一个链接,用户点击进去链接就是刚才发的表情,用户可以保存表情?

    求微信公众号开发接口-php如何实现获取用户发送的微信表情,并返回一个链接,用户点击进去链接就是刚才发的表情,用户就可以保存表情到手机? 需求描述 1.用户在公众号对话框发送微信表情(GIF) 2.公 ...

  4. php 公众号打开小程序,微信公众号图文消息新增两种进入小程序的方式

    终于不再是凌晨--就在刚刚,微信宣布小程序的能力再次升级.除了添加小程序卡片外,公众号图文消息新增两种进入小程序的方式:支持通过蓝色文字链接或图片链接跳转到小程序. 1.推送形式更多样 公众号运营者在 ...

  5. 微信公众号开发接收图片消息,获取用户发送图片的media_id

    现在的手机都有拍照功能, 而且人们拍完照后, 喜欢跟朋友分享. 微信公众号也提供了一个功能, 允许你的粉丝在后台回复图片, 你可以通过公众平台提供的api接口, 获取到图片media_id, 然后把图 ...

  6. 微信公众号开发之生成并扫描带参数的二维码

    生成带参数二维码详见微信公众平台之生成带参数的二维码 具体步骤:可在微信测试平台https://mp.weixin.qq.com/debug进行生成 生成结果如下: 拿到ticket 请求 https ...

  7. 公众号h5获取手机号权限_微信公众号开发之网页授权(获取用户信息)

    这次暑假留在学校参与工作室的项目,对微信公众号比较感兴趣,所以参与这方面的学习研究. 昨天完成了关于网页授权,获取用户信息方面的功能,所以乘热打铁,写上一篇.实现本篇涉及的 功能,还需要完成一些基础. ...

  8. python发微信红包_微信公众号开发小记——5.python微信红包

    描述 有时候产品有这么一些需求,当用户满足一定条件时,给他发一定金额的红包. 微信各个服务是独立的,比较蛋疼,要用红包功能,首先你需要注册一个微信商户平台账号. 代码位置 分支pay-20160802 ...

  9. 微信公众号开发之网页授权认证获取用户的详细信息,实现自动登陆

    原创声明:本文转来源本人另一博客[http://blog.csdn.net/liaohaojian/article/details/70175835]绝非他人处转载 从接触公众号到现在,开发维护了2个 ...

最新文章

  1. linux路由命令大全,常用Linux路由命令
  2. WINCE6.0+S3C2443的启动过程---eboot2
  3. bartender外部表不是预期格式_三张表轻松搞定项目计划
  4. 疯子的算法总结(六) 复杂排序算法 ② 桶排序
  5. sql 中 limit 与 limit,offset连用的区别
  6. linux的find命令满屏权限不够提示
  7. 有了async/await,你可以丢掉promise链了
  8. mercury无线路由器设置服务器无响应,有了这款路由器,从此卡顿不存在
  9. 使用 shell 在多服务器上批量操作
  10. vue-cli3 vue.config.js配置
  11. CString和string的互相转换
  12. 使用WireShark协议分析仪来分析ICMP与FTP协议
  13. Scrapy 爬虫开启debug调试
  14. VMware 配置虚拟机固定IP指南
  15. JAVA 利用牛顿迭代公式开方
  16. java 7zip分卷压缩_7zip分卷压缩,rar分卷压缩文件
  17. apt cyg 安装php,Cygwin的安装及使用apt-cyg管理软件包
  18. DLL中无法定位程序输入点inflateReset2于动态链接库
  19. MySQL中varchar最大长度是多少(真正的官网解释,事实说话)
  20. python 删除pdf页面_Python脚本使用pyPDF删除空白页面

热门文章

  1. Spring 3 MVC and XML example
  2. ubuntu16.04忘了root密码
  3. [每日一问]虚拟化网络设计中为什么建议采用链路聚合
  4. Android一个完整的项目转成SDK提供给第三方嵌入
  5. gentoo下gnome的抓图功能
  6. koa 接口返回数据_一文搞定 Koa 中间件实现原理
  7. Arduino方式开发ESP32笔记:使用Preferences保存数据
  8. 2008年10月热点问题!(Platform)
  9. 迎接奥运会 里约把机场的IT建设翻新了下
  10. 开发人员学Linux(8):CentOS7编译安装Subversion及Apache并集成