前言
研究微信的一系列開發已經一段時間了,將自己的開發過程記錄了下來,這次先介紹的是如何在微信的內置瀏覽器上通過授權獲取用戶信息。具體實現的是,用戶關注了公衆號,點擊公衆號下方的菜單在微信中進入公衆號的網站(比如你公司的網站首頁),在進入的時候通過授權獲取用戶信息。
要實現上述功能必須得有一個具有網頁授權功能的微信公衆號或者服務號,進入 微信公衆平臺,在開發–>接口權限看到如下就說明有授權功能,沒有的話得去申請:
其次還得在設置–>公衆號設置–>功能設置–>網頁授權域名裏填寫你的授權域名,其中還要下載一個 txt文件並放在服務器上,注意一點的是必須放在項目的根目錄並且要能訪問到,比如你用nginx的話必須配置它的路徑。
實現過程
- 服務器
先購買服務器,然後設置服務器的域名,比如設置域名爲:www.show.netcome.net
。 - 配置公衆號收集信息
首先得有一個有網頁授權功能的公衆號,然後在開發–>基本配置–>公衆號開發信息裏找到公衆號的開發者ID(AppID)和開發者密碼(AppSecret)
並記錄下來,其次在設置–>公衆號設置–>功能設置–>網頁授權域名下填寫上面的域名(注意不要加http://等協議頭,下面寫得很清楚)並將下圖中藍色的txt文件下載下來,後面需要用到:
- 接口流程
要想獲取用戶信息就得要用戶同意,這個過程分爲主要的三步,第一先請求 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 = ["<xml>"]
for k in dic.keys():
xml.append("<{0}>{1}</{0}>".format(k, dic[k]))
xml.append("</xml>")
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編碼就可以正常顯示了連表情也可以顯示在微信自帶瀏覽器的網頁上哦。
有問題歡迎留言交流。
另外,哪位大佬有空閒的公衆號(有開發權限的)來一起開發網站的,私,不勝感激。。