wechat.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. # 微信公众号相关接口
  2. import urllib.parse
  3. import requests
  4. import json
  5. import time
  6. import pytz
  7. from backend.settings import WECHAT_ID_SECRET
  8. from backend.models import WeChatAccessToken, JsapiAccessToken
  9. from datetime import datetime, timedelta
  10. from backend.functions import HttpRequest, get_nonce_str, SHA1, service_log
  11. # wechat access token management
  12. class AccessTokenManagement:
  13. def __init__(self, application_name):
  14. self.application = application_name # application_name用于存在本地数据库,和WX客户端没有关系
  15. def request_new_token(self):
  16. url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + WECHAT_ID_SECRET['appID']\
  17. + '&secret=' + WECHAT_ID_SECRET['AppSecret']
  18. res = urllib.request.urlopen(url)
  19. values = eval(res.read())
  20. wechat_token = WeChatAccessToken.search_by_application(self.application)
  21. if wechat_token is None:
  22. wechat_token = WeChatAccessToken()
  23. wechat_token.application = self.application
  24. try:
  25. wechat_token.accessTokenKey = values['access_token']
  26. wechat_token.save()
  27. except Exception as e:
  28. print(e)
  29. service_log("微信获取access token错误")
  30. service_log(values['errmsg'])
  31. def get_token(self):
  32. wechat_token = WeChatAccessToken.search_by_application(self.application)
  33. if wechat_token is None:
  34. self.request_new_token()
  35. wechat_token = WeChatAccessToken.search_by_application(self.application)
  36. utc = pytz.UTC
  37. if datetime.utcnow().replace(tzinfo=utc) > (wechat_token.requestTime + timedelta(seconds=7200 - 300)).replace(tzinfo=utc):
  38. self.request_new_token()
  39. wechat_token = WeChatAccessToken.search_by_application(self.application)
  40. return wechat_token.accessTokenKey
  41. # wechat jsapi token management
  42. # 参考文档 https://mp.weixin.qq.com/wiki?action=doc&id=mp1421141115&t=0.9173760134966377#62
  43. class JsapiTokenManagement:
  44. def __init__(self, application_name):
  45. self.application = application_name # application_name用于存在本地数据库,和WX客户端没有关系
  46. def request_new_token(self):
  47. atm = AccessTokenManagement()
  48. access_token = atm.get_token()
  49. url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi'
  50. res = urllib.request.urlopen(url)
  51. values = eval(res.read())
  52. jsapi_token = JsapiAccessToken.search_by_application(self.application)
  53. if jsapi_token is None:
  54. jsapi_token = JsapiAccessToken()
  55. jsapi_token.application = self.application
  56. jsapi_token.accessTokenKey = values['ticket']
  57. jsapi_token.save()
  58. def get_token(self):
  59. jsapi_token = JsapiAccessToken.search_by_application(self.application)
  60. if jsapi_token is None:
  61. self.request_new_token()
  62. jsapi_token = JsapiAccessToken.search_by_application(self.application)
  63. if datetime.now() > jsapi_token.requestTime + timedelta(seconds=7200 - 300):
  64. self.request_new_token()
  65. jsapi_token = JsapiAccessToken.search_by_application(self.application)
  66. return jsapi_token.accessTokenKey
  67. # 微信微信网页授权
  68. class WeChatOA2:
  69. def __init__(self):
  70. self.base_url = 'https://open.weixin.qq.com/connect/oauth2/authorize?'
  71. # state只接受a-zA-Z0-9
  72. def snsapi_base(self, state):
  73. final_url = self.base_url + 'appid=' + WECHAT_ID_SECRET['appID']
  74. final_url = final_url + '&redirect_uri=' + urllib.parse.quote(WECHAT_ID_SECRET['redirect_uri'])
  75. final_url = final_url + '&response_type=code'
  76. final_url = final_url + '&scope=snsapi_base'
  77. final_url = final_url + '&state=' + state
  78. final_url = final_url + '#wechat_redirect'
  79. print(final_url)
  80. return final_url
  81. def snsapi_userinfo(self, state):
  82. final_url = self.base_url + 'appid=' + WECHAT_ID_SECRET['appID']
  83. final_url = final_url + '&redirect_uri=' + urllib.parse.quote(WECHAT_ID_SECRET['redirect_uri'])
  84. final_url = final_url + '&response_type=code'
  85. final_url = final_url + '&scope=snsapi_userinfo'
  86. final_url = final_url + '&state=' + state
  87. final_url = final_url + '#wechat_redirect'
  88. print(final_url)
  89. return final_url
  90. # 微信模板消息发送
  91. # 开发参考页面 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277
  92. class WeChatMsg:
  93. def __init__(self, openid, template_id, application_name, url=None, miniprogram=None, pagepath=None):
  94. self.POST_content = {
  95. 'touser': openid,
  96. 'template_id': template_id,
  97. 'url': url, # 模板跳转链接
  98. 'miniprogram': miniprogram,
  99. 'appid': WECHAT_ID_SECRET['appID'],
  100. 'pagepath': pagepath,
  101. }
  102. self.application_name = application_name
  103. self.first = {}
  104. self.remark = {}
  105. self.keywords = {}
  106. def set_first(self, value, color='#000000'):
  107. self.first = {'first': {'value': value, 'color': color}}
  108. def set_remark(self, value, color='#000000'):
  109. self.remark = {'remark': {'value': value, 'color': color}}
  110. def add_keyboard(self, value, color='#000000'):
  111. l = len(self.keywords)
  112. new_keyboard = {'keyword{}'.format(l + 1): {'value': value, 'color': color}}
  113. # 从字典中取值 https://blog.csdn.net/weixin_43069755/article/details/85005682
  114. self.keywords = {**self.keywords, **new_keyboard}
  115. return self.keywords
  116. def submit(self):
  117. data = {'data': {**self.first, **self.keywords, **self.remark}}
  118. self.POST_content = {**self.POST_content, **data}
  119. POST_data = json.dumps(self.POST_content)
  120. atm = AccessTokenManagement(application_name=self.application_name)
  121. access_token = atm.get_token()
  122. url = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={}'.format(access_token)
  123. resp = requests.post(url, data=POST_data.encode('utf-8'), headers={'Content-Type': 'text/xml'})
  124. msg = resp.text.encode('ISO-8859-1').decode('utf-8')
  125. return msg
  126. # JSAPI 调用
  127. # https://mp.weixin.qq.com/wiki?action=doc&id=mp1421141115&t=0.9173760134966377#62
  128. class JSAPI:
  129. def __init__(self, url):
  130. self.data = {'timestamp': str(int(time.time())), 'noncestr': get_nonce_str(), 'url': url}
  131. def get_sign(self):
  132. # 计算签名
  133. jtm = JsapiTokenManagement()
  134. self.data['jsapi_ticket'] = jtm.get_token()
  135. keys, paras = sorted(self.data), []
  136. paras = ['{}={}'.format(key, self.data[key]) for key in keys] # and kwargs[key] != '']
  137. stringA = '&'.join(paras)
  138. stringSignTemp = stringA # + '&key=' + WECHAT_ID_SECRET['wx_mch_api_key']
  139. sign = SHA1(stringSignTemp)
  140. self.data['signature'] = sign
  141. def get_parameter(self):
  142. self.get_sign()
  143. self.data['appId'] = WECHAT_ID_SECRET['appID']
  144. return self.data