Django微信公众号开发(一)公众号内网页授权登录后微信获取用户信息

前言

  研究微信的一系列开发已经一段时间了,将自己的开发过程记录了下来,这次先介绍的是如何在微信的内置浏览器上通过授权获取用户信息。具体实现的是,用户关注了公众号,点击公众号下方的菜单在微信中进入公众号的网站(比如你公司的网站首页),在进入的时候通过授权获取用户信息。
  要实现上述功能必须得有一个具有网页授权功能的微信公众号或者服务号,进入 微信公众平台,在开发–>接口权限看到如下就说明有授权功能,没有的话得去申请:
这里写图片描述
  其次还得在设置–>公众号设置–>功能设置–>网页授权域名里填写你的授权域名,其中还要下载一个 txt文件并放在服务器上,注意一点的是必须放在项目的根目录并且要能访问到,比如你用nginx的话必须配置它的路径。

实现过程

  • 服务器
      先购买服务器,然后设置服务器的域名,比如设置域名为:www.show.netcome.net
  • 配置公众号收集信息
      首先得有一个有网页授权功能的公众号,然后在开发–>基本配置–>公众号开发信息里找到公众号的开发者ID(AppID)和开发者密码(AppSecret)
    并记录下来,其次在设置–>公众号设置–>功能设置–>网页授权域名下填写上面的域名(注意不要加http://等协议头,下面写得很清楚)并将下图中蓝色的txt文件下载下来,后面需要用到:
    Django微信公众号开发(一)公众号内网页授权登录后微信获取用户信息_第1张图片
  • 接口流程
      要想获取用户信息就得要用户同意,这个过程分为主要的三步,第一先请求 code:code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。第二步通过刚请求来的 code去请求access_token和openid,第三部就是通过刚获取的access_token和openid来请求用户信息。
  • python代码如下(如果你想知道细节,可以去查看官方文档):
# -*- coding: utf-8 -*-
# ----------------------------------------------
# @Time    : 18-3-21 下午1:36
# @Author  : YYJ
# @File    : WechatAPI.py
# @CopyRight: ZDWL
# ----------------------------------------------
import hashlib
import random
import time
from urllib import parse
from xml.etree.ElementTree import fromstring

import requests

from src.beauty.main.wechat.config import wechatConfig


class WechatAPI(object):
    def __init__(self):
        self.config = wechatConfig
        self._access_token = None
        self._openid = None

    @staticmethod
    def process_response_login(rsp):
        """解析微信登录返回的json数据,返回相对应的dict, 错误信息"""
        if 200 != rsp.status_code:
            return None, {'code': rsp.status_code, 'msg': 'http error'}
        try:
            content = rsp.json()

        except Exception as e:
            return None, {'code': 9999, 'msg': e}
        if 'errcode' in content and content['errcode'] != 0:
            return None, {'code': content['errcode'], 'msg': content['errmsg']}

        return content, None

    @staticmethod
    def create_time_stamp():
        """产生时间戳"""
        now = time.time()
        return int(now)

    @staticmethod
    def create_nonce_str(length=32):
        """产生随机字符串,不长于32位"""
        chars = "abcdefghijklmnopqrstuvwxyz0123456789"
        strs = []
        for x in range(length):
            strs.append(chars[random.randrange(0, len(chars))])
        return "".join(strs)

    @staticmethod
    def xml_to_array(xml):
        """将xml转为array"""
        array_data = {}
        root = fromstring(xml)
        for child in root:
            value = child.text
            array_data[child.tag] = value
        return array_data

    def array_to_xml(self, dic, sign_name=None):
        """array转xml"""
        if sign_name is not None:
            dic[sign_name] = self.get_sign()
        xml = [""]
        for k in dic.keys():
            xml.append("<{0}>{1}".format(k, dic[k]))
        xml.append("")
        return "".join(xml)


class WechatLogin(WechatAPI):
    def get_code_url(self):
        """微信内置浏览器获取网页授权code的url"""
        url = self.config.defaults.get('wechat_browser_code') + (
            '?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect' %
            (self.config.APPID, parse.quote(self.config.REDIRECT_URI),
             self.config.SCOPE, self.config.STATE if self.config.STATE else ''))
        return url

    def get_code_url_pc(self):
        """pc浏览器获取网页授权code的url"""
        url = self.config.defaults.get('pc_QR_code') + (
            '?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect' %
            (self.config.APPID, parse.quote(self.config.REDIRECT_URI), self.config.PC_LOGIN_SCOPE,
             self.config.STATE if self.config.STATE else ''))
        return url

    def get_access_token(self, code):
        """获取access_token"""
        params = {
            'appid': self.config.APPID,
            'secret': self.config.APPSECRET,
            'code': code,
            'grant_type': 'authorization_code'
        }
        token, err = self.process_response_login(requests
                                                 .get(self.config.defaults.get('wechat_browser_access_token'),
                                                      params=params))
        if not err:
            self._access_token = token['access_token']
            self._openid = token['openid']
        return self._access_token, self._openid

    def get_user_info(self, access_token, openid):
        """获取用户信息"""
        params = {
            'access_token': access_token,
            'openid': openid,
            'lang': self.config.LANG
        }
        return self.process_response_login(requests
                                           .get(self.config.defaults.get('wechat_browser_user_info'), params=params))

  上面导入了一个参数文件,内容填写如下:

# -*- coding: utf-8 -*-
# ----------------------------------------------
# @Time    : 18-3-21 上午11:50
# @Author  : YYJ
# @File    : wechatConfig.py
# @CopyRight: ZDWL
# ----------------------------------------------

"""
微信公众号和商户平台信息配置文件
"""


# ----------------------------------------------微信公众号---------------------------------------------- #
# 公众号appid
APPID = 'appid'
# 公众号AppSecret
APPSECRET = 'appsecret'


# ----------------------------------------------微信商户平台---------------------------------------------- #
# 商户id
MCH_ID = 'mch_id'

API_KEY = 'api秘钥'


# ----------------------------------------------回调页面---------------------------------------------- #
# 用户授权获取code后的回调页面,如果需要实现验证登录就必须填写
REDIRECT_URI = 'http://www.show.netcome.net/index'
PC_LOGIN_REDIRECT_URI = 'http://www.show.netcome.net/index'

defaults = {
    # 微信内置浏览器获取code微信接口
    'wechat_browser_code': 'https://open.weixin.qq.com/connect/oauth2/authorize',
    # 微信内置浏览器获取access_token微信接口
    'wechat_browser_access_token': 'https://api.weixin.qq.com/sns/oauth2/access_token',
    # 微信内置浏览器获取用户信息微信接口
    'wechat_browser_user_info': 'https://api.weixin.qq.com/sns/userinfo',
    # pc获取登录二维码接口
    'pc_QR_code': 'https://open.weixin.qq.com/connect/qrconnect',
    # pc获取登录二维码接口
    # 'pc_QR_code': 'https://api.weixin.qq.com/sns/userinfo',
}


SCOPE = 'snsapi_userinfo'
PC_LOGIN_SCOPE = 'snsapi_login'
STATE = ''
LANG = 'zh_CN'

  以上信息中你必须填上APPID、APPSECRET、REDIRECT_URI,其中SCOPE可以为snsapi_userinfo或者snsapi_base。
  然后在你Django的views.py中写下面三个view:

from django.views.generic import View
from login
from django.http import HttpResponseRedirect
from django.http import HttpResponse, HttpResponseServerError
from django.shortcuts import render, redirect
from src.beauty.main.wechat.utils.WechatAPI import WechatLogin


class WechatViewSet(View):
    wechat_api = WechatLogin()


class AuthView(WechatViewSet):
    def get(self, request):
        url = self.wechat_api.get_code_url()
        return redirect(url)


class GetInfoView(WechatViewSet):
    def get(self, request):
        if 'code' in request.GET:
            code = request.GET['code']
            token, openid = self.wechat_api.get_access_token(code)
            if token is None or openid is None:
                return HttpResponseServerError('get code error')
            user_info, error = self.wechat_api.get_user_info(token, openid)
            if error:
                return HttpResponseServerError('get access_token error')
            user_data = {
                'nickname': user_info['nickname'],
                'sex': user_info['sex'],
                'province': user_info['province'].encode('iso8859-1').decode('utf-8'),
                'city': user_info['city'].encode('iso8859-1').decode('utf-8'),
                'country': user_info['country'].encode('iso8859-1').decode('utf-8'),
                'avatar': user_info['headimgurl'],
                'openid': user_info['openid']
            }
            user = BeautyUsers.objects.filter(is_effective=True).filter(wechat=user_data['openid'])
            if user.count() == 0:
                user = BeautyUsers.objects.create(username=user_data['nickname'],
                                                  wechat_avatar=user_data['avatar'],
                                                  wechat=user_data['openid'],
                                                  password='')
                login(request, user)
            else:
                login(request, user.first())
            # 授权登录成功,进入主页
            return home(request)

  还有一个urls.py文件做如下写法:

from django.conf.urls import url
from src.beauty.main.wechat.apps.index import views
from src.beauty.main.wechat.apps.index.views import AuthView, GetInfoView

urlpatterns = [
    url(r'^$', views.home),
    url(r'^auth/$', AuthView.as_view()),
    url(r'^index$', GetInfoView.as_view()),
]

  解释一下,第一个url路由是你验证过后要进入的网页,第二个为验证授权的请求页面,用户在公众号中点击菜单就会请求第二个http://www.show.netcome.net/auth/路由,在这个路由里(AuthView),我们重定向了,去请求了微信的接口,为了获取当前点击用户的code值,请求成功后微信会转向回调页面(在参数文件中配置的http://www.show.netcome.net/index)也就是来请求上面我们的第三个路由。注意请求code成功后微信会以get的方式回调我们的这个路由,并且携带code和state的值,格式如:http://www.show.netcome.net/index/?code=CODE&state=STATE,我们就可以在GetInfoView这个view中获取到code值,然后去请求access_token和openid(self.wechat_api.get_access_token(code)函数,里面有requests.get(url)的http请求,也就是在客户端请求中嵌入了一个服务端请求,这里是服务端发起一个http去请求微信服务端的这个获取access_token的接口,服务端请求到access_token的话就再发起请求去获取用户信息),通过请求到的access_token和openid去请求用户信息(self.wechat_api.get_user_info(token, openid)函数,里面也包含了一个内嵌的服务器端http请求)。

  • 在公众号的功能–>自定义菜单中修改如下:
    Django微信公众号开发(一)公众号内网页授权登录后微信获取用户信息_第2张图片

      然后将你的项目,通过nginx+uwsgi部署到服务器上就可以了(配置方法见我另一篇博客),获取到的信息在views.py的GetInfoView中,其中获取到的nickname不要使用.encode(‘iso8859-1’).decode(‘utf-8’)编码为utf-8保存到数据库,因为微信昵称中可以包含表情,表情由4个字节组成,utf-8为三字节,所以一utf-8编码保存在数据库会出错,这里不用编码直接保存,在拿出来使用的时候再对其进行utf-8编码就可以正常显示了连表情也可以显示在微信自带浏览器的网页上哦。
      有问题欢迎留言交流。
      另外,哪位大佬有空闲的公众号(有开发权限的)来一起开发网站的,私,不胜感激。。

你可能感兴趣的:(Django)