前言
研究微信的一系列开发已经一段时间了,将自己的开发过程记录了下来,这次先介绍的是如何在微信的内置浏览器上通过授权获取用户信息。具体实现的是,用户关注了公众号,点击公众号下方的菜单在微信中进入公众号的网站(比如你公司的网站首页),在进入的时候通过授权获取用户信息。
要实现上述功能必须得有一个具有网页授权功能的微信公众号或者服务号,进入 微信公众平台,在开发–>接口权限看到如下就说明有授权功能,没有的话得去申请:
其次还得在设置–>公众号设置–>功能设置–>网页授权域名里填写你的授权域名,其中还要下载一个 txt文件并放在服务器上,注意一点的是必须放在项目的根目录并且要能访问到,比如你用nginx的话必须配置它的路径。
实现过程
www.show.netcome.net
。# -*- 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}{0}>".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请求)。
然后将你的项目,通过nginx+uwsgi部署到服务器上就可以了(配置方法见我另一篇博客),获取到的信息在views.py的GetInfoView中,其中获取到的nickname不要使用.encode(‘iso8859-1’).decode(‘utf-8’)编码为utf-8保存到数据库,因为微信昵称中可以包含表情,表情由4个字节组成,utf-8为三字节,所以一utf-8编码保存在数据库会出错,这里不用编码直接保存,在拿出来使用的时候再对其进行utf-8编码就可以正常显示了连表情也可以显示在微信自带浏览器的网页上哦。
有问题欢迎留言交流。
另外,哪位大佬有空闲的公众号(有开发权限的)来一起开发网站的,私,不胜感激。。