# 微信公众号相关接口 import urllib.parse import requests import json import time import pytz from backend.settings import WECHAT_ID_SECRET from backend.models import WeChatAccessToken, JsapiAccessToken from datetime import datetime, timedelta from backend.functions import HttpRequest, get_nonce_str, SHA1, service_log # wechat access token management class AccessTokenManagement: def __init__(self, application_name): self.application = application_name # application_name用于存在本地数据库,和WX客户端没有关系 def request_new_token(self): url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + WECHAT_ID_SECRET['appID']\ + '&secret=' + WECHAT_ID_SECRET['AppSecret'] res = urllib.request.urlopen(url) values = eval(res.read()) wechat_token = WeChatAccessToken.search_by_application(self.application) if wechat_token is None: wechat_token = WeChatAccessToken() wechat_token.application = self.application try: wechat_token.accessTokenKey = values['access_token'] wechat_token.save() except Exception as e: print(e) service_log("微信获取access token错误") service_log(values['errmsg']) def get_token(self): wechat_token = WeChatAccessToken.search_by_application(self.application) if wechat_token is None: self.request_new_token() wechat_token = WeChatAccessToken.search_by_application(self.application) utc = pytz.UTC if datetime.utcnow().replace(tzinfo=utc) > (wechat_token.requestTime + timedelta(seconds=7200 - 300)).replace(tzinfo=utc): self.request_new_token() wechat_token = WeChatAccessToken.search_by_application(self.application) return wechat_token.accessTokenKey # wechat jsapi token management # 参考文档 https://mp.weixin.qq.com/wiki?action=doc&id=mp1421141115&t=0.9173760134966377#62 class JsapiTokenManagement: def __init__(self, application_name): self.application = application_name # application_name用于存在本地数据库,和WX客户端没有关系 def request_new_token(self): atm = AccessTokenManagement() access_token = atm.get_token() url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi' res = urllib.request.urlopen(url) values = eval(res.read()) jsapi_token = JsapiAccessToken.search_by_application(self.application) if jsapi_token is None: jsapi_token = JsapiAccessToken() jsapi_token.application = self.application jsapi_token.accessTokenKey = values['ticket'] jsapi_token.save() def get_token(self): jsapi_token = JsapiAccessToken.search_by_application(self.application) if jsapi_token is None: self.request_new_token() jsapi_token = JsapiAccessToken.search_by_application(self.application) if datetime.now() > jsapi_token.requestTime + timedelta(seconds=7200 - 300): self.request_new_token() jsapi_token = JsapiAccessToken.search_by_application(self.application) return jsapi_token.accessTokenKey # 微信微信网页授权 class WeChatOA2: def __init__(self): self.base_url = 'https://open.weixin.qq.com/connect/oauth2/authorize?' # state只接受a-zA-Z0-9 def snsapi_base(self, state): final_url = self.base_url + 'appid=' + WECHAT_ID_SECRET['appID'] final_url = final_url + '&redirect_uri=' + urllib.parse.quote(WECHAT_ID_SECRET['redirect_uri']) final_url = final_url + '&response_type=code' final_url = final_url + '&scope=snsapi_base' final_url = final_url + '&state=' + state final_url = final_url + '#wechat_redirect' print(final_url) return final_url def snsapi_userinfo(self, state): final_url = self.base_url + 'appid=' + WECHAT_ID_SECRET['appID'] final_url = final_url + '&redirect_uri=' + urllib.parse.quote(WECHAT_ID_SECRET['redirect_uri']) final_url = final_url + '&response_type=code' final_url = final_url + '&scope=snsapi_userinfo' final_url = final_url + '&state=' + state final_url = final_url + '#wechat_redirect' print(final_url) return final_url # 微信模板消息发送 # 开发参考页面 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277 class WeChatMsg: def __init__(self, openid, template_id, application_name, url=None, miniprogram=None, pagepath=None): self.POST_content = { 'touser': openid, 'template_id': template_id, 'url': url, # 模板跳转链接 'miniprogram': miniprogram, 'appid': WECHAT_ID_SECRET['appID'], 'pagepath': pagepath, } self.application_name = application_name self.first = {} self.remark = {} self.keywords = {} def set_first(self, value, color='#000000'): self.first = {'first': {'value': value, 'color': color}} def set_remark(self, value, color='#000000'): self.remark = {'remark': {'value': value, 'color': color}} def add_keyboard(self, value, color='#000000'): l = len(self.keywords) new_keyboard = {'keyword{}'.format(l + 1): {'value': value, 'color': color}} # 从字典中取值 https://blog.csdn.net/weixin_43069755/article/details/85005682 self.keywords = {**self.keywords, **new_keyboard} return self.keywords def submit(self): data = {'data': {**self.first, **self.keywords, **self.remark}} self.POST_content = {**self.POST_content, **data} POST_data = json.dumps(self.POST_content) atm = AccessTokenManagement(application_name=self.application_name) access_token = atm.get_token() url = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={}'.format(access_token) resp = requests.post(url, data=POST_data.encode('utf-8'), headers={'Content-Type': 'text/xml'}) msg = resp.text.encode('ISO-8859-1').decode('utf-8') return msg # JSAPI 调用 # https://mp.weixin.qq.com/wiki?action=doc&id=mp1421141115&t=0.9173760134966377#62 class JSAPI: def __init__(self, url): self.data = {'timestamp': str(int(time.time())), 'noncestr': get_nonce_str(), 'url': url} def get_sign(self): # 计算签名 jtm = JsapiTokenManagement() self.data['jsapi_ticket'] = jtm.get_token() keys, paras = sorted(self.data), [] paras = ['{}={}'.format(key, self.data[key]) for key in keys] # and kwargs[key] != ''] stringA = '&'.join(paras) stringSignTemp = stringA # + '&key=' + WECHAT_ID_SECRET['wx_mch_api_key'] sign = SHA1(stringSignTemp) self.data['signature'] = sign def get_parameter(self): self.get_sign() self.data['appId'] = WECHAT_ID_SECRET['appID'] return self.data