tornado 短信验证码

Python3接入云通讯短信

API接入:三个.py文件放在一个文件夹下,启动一下SendTemplateSMS.py文件就行。

SendTemplateSMS.py
 1 from CCPRestSDK import REST
 2 
 3 # import ConfigParser
 4 
 5 # 主帐号
 6 accountSid = '***'
 7 
 8 # 主帐号Token
 9 accountToken = '***'
10 
11 # 应用Id
12 appId = '***'
13 
14 # 请求地址,格式如下,不需要写http://
15 serverIP = 'app.cloopen.com'
16 
17 # 请求端口
18 serverPort = '8883'
19 
20 # REST版本号
21 softVersion = '2013-12-26'
22 
23 
24 # 发送模板短信
25 # @param to 手机号码
26 # @param datas 内容数据 格式为数组 例如:{'12','34'},如不需替换请填 ''
27 # @param $tempId 模板Id
28 
29 class CCP(object):
30     def __init__(self):
31         self.rest = REST(serverIP, serverPort, softVersion)
32         self.rest.setAccount(accountSid, accountToken)
33         self.rest.setAppId(appId)
34 
35     @staticmethod
36     def instance():
37         if not hasattr(CCP, "_instance"):
38             CCP._instance = CCP()
39         return CCP._instance
40 
41     def sendTemplateSMS(self, to, datas, tempId):
42         try:
43             result = self.rest.sendTemplateSMS(to, datas, tempId)
44         except Exception as e:
45             # logging.error(e)
46             raise e
47         # print result
48         # for k, v in result.iteritems():
49         #     if k == 'templateSMS':
50         #         for k, s in v.iteritems():
51         #             print '%s:%s' % (k, s)
52         #     else:
53         #         print '%s:%s' % (k, v)
54         success = "<statusCode>000000</statusCode>"
55         if success in result:
56             return True
57         else:
58             return False
59 
60 ccp = CCP.instance()
61 
62 if __name__ == "__main__":
63     ccp = CCP.instance()
64     # 1代表模板ID,下载SDK的官网api文档有说明
65     ret = ccp.sendTemplateSMS("***", ["aaaa", "1"], 1)
66 
67     print(ret)

CCPRestSDK.py
  1 # -*- coding: UTF-8 -*-
  2 #  Copyright (c) 2014 The CCP project authors. All Rights Reserved.
  3 #
  4 #  Use of this source code is governed by a Beijing Speedtong Information Technology Co.,Ltd license
  5 #  that can be found in the LICENSE file in the root of the web site.
  6 #
  7 #   http://www.yuntongxun.com
  8 #
  9 #  An additional intellectual property rights grant can be found
 10 #  in the file PATENTS.  All contributing project authors may
 11 #  be found in the AUTHORS file in the root of the source tree.
 12 
 13 from hashlib import md5
 14 import base64
 15 import datetime
 16 import urllib.request
 17 import requests
 18 import json
 19 from xmltojson import xmltojson
 20 from xml.dom import minidom
 21 
 22 
 23 class REST:
 24     AccountSid = ''
 25     AccountToken = ''
 26     AppId = ''
 27     SubAccountSid = ''
 28     SubAccountToken = ''
 29     ServerIP = ''
 30     ServerPort = ''
 31     SoftVersion = ''
 32     Iflog = True  # 是否打印日志
 33     Batch = ''  # 时间戳
 34     BodyType = 'xml'  # 包体格式,可填值:json 、xml
 35 
 36     # 初始化
 37     # @param serverIP       必选参数    服务器地址
 38     # @param serverPort     必选参数    服务器端口
 39     # @param softVersion    必选参数    REST版本号
 40     def __init__(self, ServerIP, ServerPort, SoftVersion):
 41 
 42         self.ServerIP = ServerIP
 43         self.ServerPort = ServerPort
 44         self.SoftVersion = SoftVersion
 45 
 46     # 设置主帐号
 47     # @param AccountSid  必选参数    主帐号
 48     # @param AccountToken  必选参数    主帐号Token
 49 
 50     def setAccount(self, AccountSid, AccountToken):
 51         self.AccountSid = AccountSid
 52         self.AccountToken = AccountToken
 53 
 54         # 设置子帐号
 55 
 56     #
 57     # @param SubAccountSid  必选参数    子帐号
 58     # @param SubAccountToken  必选参数    子帐号Token
 59 
 60     def setSubAccount(self, SubAccountSid, SubAccountToken):
 61         self.SubAccountSid = SubAccountSid
 62         self.SubAccountToken = SubAccountToken
 63 
 64         # 设置应用ID
 65 
 66     #
 67     # @param AppId  必选参数    应用ID
 68 
 69     def setAppId(self, AppId):
 70         self.AppId = AppId
 71 
 72     def log(self, url, body, data):
 73         print('这是请求的URL:')
 74         print(url)
 75         print('这是请求包体:')
 76         print(body)
 77         print('这是响应包体:')
 78         print(data)
 79         print('********************************')
 80 
 81     # 创建子账号
 82     # @param friendlyName   必选参数      子帐号名称
 83     def CreateSubAccount(self, friendlyName):
 84 
 85         self.accAuth()
 86         nowdate = datetime.datetime.now()
 87         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
 88         # 生成sig
 89         signature = self.AccountSid + self.AccountToken + self.Batch
 90         sig = md5(signature.encode()).hexdigest().upper()
 91         # 拼接URL
 92         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/SubAccounts?sig=" + sig
 93         # 生成auth
 94         src = self.AccountSid + ":" + self.Batch
 95         auth = base64.encodestring(src.encode()).strip().decode()
 96         req = urllib.request.Request(url)
 97         self.setHttpHeader(req)
 98         req.add_header("Authorization", auth)
 99         # xml格式
100         body = '''<?xml version="1.0" encoding="utf-8"?><SubAccount><appId>%s</appId>\
101             <friendlyName>%s</friendlyName>\
102             </SubAccount>\
103             ''' % (self.AppId, friendlyName)
104 
105         if self.BodyType == 'json':
106             # json格式
107             body = '''{"friendlyName": "%s", "appId": "%s"}''' % (friendlyName, self.AppId)
108         data = ''
109         req.data = body
110         try:
111             # res = urllib.request.urlopen(req)
112             # data = res.read()
113             # res.close()
114             res = requests.post(url, headers=req.headers, data=req.data)
115             # print(res.status_code, res.content, res.text, )
116             data = res.text
117             # if self.BodyType == 'json':
118             #     # json格式
119             #     locations = json.loads(data)
120             # else:
121             #     # xml格式
122             #     xtj = xmltojson()
123             #     locations = xtj.main(data)
124             if self.Iflog:
125                 self.log(url, body, data)
126             return data
127         except Exception as error:
128             if self.Iflog:
129                 self.log(url, body, data)
130             return {'172001': '网络错误'}
131 
132     # 获取子帐号
133     # @param startNo  可选参数    开始的序号,默认从0开始
134     # @param offset 可选参数     一次查询的最大条数,最小是1条,最大是100条
135     def getSubAccounts(self, startNo, offset):
136 
137         self.accAuth()
138         nowdate = datetime.datetime.now()
139         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
140         # 生成sig
141         signature = self.AccountSid + self.AccountToken + self.Batch
142         sig = md5(signature.encode()).hexdigest().upper()
143         # 拼接URL
144         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/GetSubAccounts?sig=" + sig
145         # 生成auth
146         src = self.AccountSid + ":" + self.Batch
147         auth = base64.encodestring(src.encode()).strip().decode()
148         req = urllib.request.Request(url)
149         self.setHttpHeader(req)
150         req.add_header("Authorization", auth)
151         # xml格式
152         body = '''<?xml version="1.0" encoding="utf-8"?><SubAccount><appId>%s</appId>\
153             <startNo>%s</startNo><offset>%s</offset>\
154             </SubAccount>\
155             ''' % (self.AppId, startNo, offset)
156 
157         if self.BodyType == 'json':
158             # json格式
159             body = '''{"appId": "%s", "startNo": "%s", "offset": "%s"}''' % (self.AppId, startNo, offset)
160         data = ''
161         req.data = body
162         try:
163             res = requests.get(url, headers=req.headers)
164             # print(res.status_code, res.content, res.text, )
165             data = res.text
166 
167             # if self.BodyType == 'json':
168             #     # json格式
169             #     locations = json.loads(data)
170             # else:
171             #     # xml格式
172             #     xtj = xmltojson()
173             #     locations = xtj.main(data)
174             if self.Iflog:
175                 self.log(url, body, data)
176             return data
177         except Exception as error:
178             if self.Iflog:
179                 self.log(url, body, data)
180             return {'172001': '网络错误'}
181 
182     # 子帐号信息查询
183     # @param friendlyName 必选参数   子帐号名称
184 
185     def querySubAccount(self, friendlyName):
186 
187         self.accAuth()
188         nowdate = datetime.datetime.now()
189         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
190         # 生成sig
191         signature = self.AccountSid + self.AccountToken + self.Batch
192         sig = md5(signature.encode()).hexdigest().upper()
193         # 拼接URL
194         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/QuerySubAccountByName?sig=" + sig
195         # 生成auth
196         src = self.AccountSid + ":" + self.Batch
197         auth = base64.encodestring(src.encode()).strip().decode()
198         req = urllib.request.Request(url)
199         self.setHttpHeader(req)
200 
201         req.add_header("Authorization", auth)
202 
203         # 创建包体
204         body = '''<?xml version="1.0" encoding="utf-8"?><SubAccount><appId>%s</appId>\
205             <friendlyName>%s</friendlyName>\
206             </SubAccount>\
207             ''' % (self.AppId, friendlyName)
208         if self.BodyType == 'json':
209             body = '''{"friendlyName": "%s", "appId": "%s"}''' % (friendlyName, self.AppId)
210         data = ''
211         req.data = body
212         try:
213             # res = urllib.request.urlopen(req)
214             # data = res.read()
215             # res.close()
216             res = requests.get(url, headers=req.headers, data=req.data)
217             # print(res.status_code, res.content, res.text, )
218             data = res.text
219 
220             # if self.BodyType == 'json':
221             #     # json格式
222             #     locations = json.loads(data)
223             # else:
224             #     # xml格式
225             #     xtj = xmltojson()
226             #     locations = xtj.main(data)
227             if self.Iflog:
228                 self.log(url, body, data)
229             return data
230         except Exception as error:
231             if self.Iflog:
232                 self.log(url, body, data)
233             return {'172001': '网络错误'}
234 
235     # 发送模板短信
236     # @param to  必选参数     短信接收彿手机号码集合,用英文逗号分开
237     # @param datas 可选参数    内容数据
238     # @param tempId 必选参数    模板Id
239     def sendTemplateSMS(self, to, datas, tempId):
240 
241         self.accAuth()
242         nowdate = datetime.datetime.now()
243         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
244         # 生成sig
245         signature = self.AccountSid + self.AccountToken + self.Batch
246         sig = md5(signature.encode()).hexdigest().upper()
247         # 拼接URL
248         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/SMS/TemplateSMS?sig=" + sig
249         # 生成auth
250         src = self.AccountSid + ":" + self.Batch
251         auth = base64.encodestring(src.encode()).strip().decode()
252         req = urllib.request.Request(url)
253         self.setHttpHeader(req)
254         req.add_header("Authorization", auth)
255         # print(req.headers)      #组装请求头
256         # 创建包体
257         b = ''
258         for a in datas:
259             b += '<data>%s</data>' % (a)
260 
261         body = '<?xml version="1.0" encoding="utf-8"?><SubAccount><datas>' + b + '</datas><to>%s</to><templateId>%s</templateId><appId>%s</appId>\
262             </SubAccount>\
263             ' % (to, tempId, self.AppId)
264         if self.BodyType == 'json':
265             # if this model is Json ..then do next code
266             b = '['
267             for a in datas:
268                 b += '"%s",' % (a)
269             b += ']'
270             body = '''{"to": "%s", "datas": %s, "templateId": "%s", "appId": "%s"}''' % (to, b, tempId, self.AppId)
271         req.data = body
272         # print(req.data)    #组装请求体
273         # 确认请求体和请求头
274         req_headers = req.headers
275         req_data = req.data
276         # print(req_headers,req_data)
277         # print("_______"*20)
278         data = ''
279         try:
280             # res = urllib.request.urlopen(req)
281             res = requests.post(url, headers=req_headers, data=req_data)
282             # print(res.status_code,res.content,res.text,)
283             data = res.text
284             # data = res.read()
285             # res.close()
286             # if self.BodyType == 'json':
287             #     # json格式
288             #     locations = json.loads(data)
289             # else:
290             #     # xml格式
291             #     xtj = xmltojson()
292             #     locations = xtj.main(data)
293             if self.Iflog:
294                 self.log(url, body, data)
295             return data
296         except Exception as error:
297             if self.Iflog:
298                 self.log(url, body, data)
299             return {'172001': '网络错误'}
300 
301     # 外呼通知
302     # @param to 必选参数    被叫号码
303     # @param mediaName 可选参数    语音文件名称,格式 wav。与mediaTxt不能同时为空。当不为空时mediaTxt属性失效。
304     # @param mediaTxt 可选参数    文本内容
305     # @param displayNum 可选参数    显示的主叫号码
306     # @param playTimes 可选参数    循环播放次数,1-3次,默认播放1次。
307     # @param respUrl 可选参数    外呼通知状态通知回调地址,云通讯平台将向该Url地址发送呼叫结果通知。
308     # @param userData 可选参数    用户私有数据
309     # @param maxCallTime 可选参数    最大通话时长
310     # @param speed 可选参数    发音速度
311     # @param volume 可选参数    音量
312     # @param pitch 可选参数    音调
313     # @param bgsound 可选参数    背景音编号
314 
315     def landingCall(self, to, mediaName, mediaTxt, displayNum, playTimes, respUrl, userData, maxCallTime, speed, volume,
316                     pitch, bgsound):
317 
318         self.accAuth()
319         nowdate = datetime.datetime.now()
320         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
321         # 生成sig
322         signature = self.AccountSid + self.AccountToken + self.Batch
323         sig = md5(signature.encode()).hexdigest().upper()
324         # 拼接URL
325         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/Calls/LandingCalls?sig=" + sig
326         # 生成auth
327         src = self.AccountSid + ":" + self.Batch
328         auth = base64.encodestring(src.encode()).strip().decode()
329         req = urllib.request.Request(url)
330         self.setHttpHeader(req)
331         req.add_header("Authorization", auth)
332 
333         # 创建包体
334         body = '''<?xml version="1.0" encoding="utf-8"?><LandingCall>\
335             <to>%s</to><mediaName>%s</mediaName><mediaTxt>%s</mediaTxt><appId>%s</appId><displayNum>%s</displayNum>\
336             <playTimes>%s</playTimes><respUrl>%s</respUrl><userData>%s</userData><maxCallTime>%s</maxCallTime><speed>%s</speed>
337             <volume>%s</volume><pitch>%s</pitch><bgsound>%s</bgsound></LandingCall>\
338             ''' % (
339             to, mediaName, mediaTxt, self.AppId, displayNum, playTimes, respUrl, userData, maxCallTime, speed, volume,
340             pitch, bgsound)
341         if self.BodyType == 'json':
342             body = '''{"to": "%s", "mediaName": "%s","mediaTxt": "%s","appId": "%s","displayNum": "%s","playTimes": "%s","respUrl": "%s","userData": "%s","maxCallTime": "%s","speed": "%s","volume": "%s","pitch": "%s","bgsound": "%s"}''' % (
343                 to, mediaName, mediaTxt, self.AppId, displayNum, playTimes, respUrl, userData, maxCallTime, speed,
344                 volume,
345                 pitch, bgsound)
346         req.data = body
347         data = ''
348         try:
349             # res = urllib.request.urlopen(req)
350             # data = res.read()
351             # res.close()
352             res = requests.post(url, headers=req.headers, data=req.data)
353             # print(res.status_code, res.content, res.text, )
354             data = res.text
355 
356             # if self.BodyType == 'json':
357             #     # json格式
358             #     locations = json.loads(data)
359             # else:
360             #     # xml格式
361             #     xtj = xmltojson()
362             #     locations = xtj.main(data)
363             if self.Iflog:
364                 self.log(url, body, data)
365             return data
366         except Exception as error:
367             if self.Iflog:
368                 self.log(url, body, data)
369             return {'172001': '网络错误'}
370 
371     # 语音验证码
372     # @param verifyCode  必选参数   验证码内容,为数字和英文字母,不区分大小写,长度4-8位
373     # @param playTimes  可选参数   播放次数,1-3次
374     # @param to 必选参数    接收号码
375     # @param displayNum 可选参数    显示的主叫号码
376     # @param respUrl 可选参数    语音验证码状态通知回调地址,云通讯平台将向该Url地址发送呼叫结果通知
377     # @param lang 可选参数    语言类型
378     # @param userData 可选参数    第三方私有数据
379 
380     def voiceVerify(self, verifyCode, playTimes, to, displayNum, respUrl, lang, userData):
381 
382         self.accAuth()
383         nowdate = datetime.datetime.now()
384         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
385         # 生成sig
386         signature = self.AccountSid + self.AccountToken + self.Batch
387         sig = md5(signature.encode()).hexdigest().upper()
388         # 拼接URL
389         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/Calls/VoiceVerify?sig=" + sig
390         # 生成auth
391         src = self.AccountSid + ":" + self.Batch
392         auth = base64.encodestring(src.encode()).strip().decode()
393         req = urllib.request.Request(url)
394         self.setHttpHeader(req)
395 
396         req.add_header("Authorization", auth)
397 
398         # 创建包体
399         body = '''<?xml version="1.0" encoding="utf-8"?><VoiceVerify>\
400             <appId>%s</appId><verifyCode>%s</verifyCode><playTimes>%s</playTimes><to>%s</to><respUrl>%s</respUrl>\
401             <displayNum>%s</displayNum><lang>%s</lang><userData>%s</userData></VoiceVerify>\
402             ''' % (self.AppId, verifyCode, playTimes, to, respUrl, displayNum, lang, userData)
403         if self.BodyType == 'json':
404             # if this model is Json ..then do next code
405             body = '''{"appId": "%s", "verifyCode": "%s","playTimes": "%s","to": "%s","respUrl": "%s","displayNum": "%s","lang": "%s","userData": "%s"}''' % (
406                 self.AppId, verifyCode, playTimes, to, respUrl, displayNum, lang, userData)
407         req.data = body
408         data = ''
409         try:
410             # res = urllib.request.urlopen(req)
411             # data = res.read()
412             # res.close()
413             res = requests.post(url, headers=req.headers, data=req.data)
414             # print(res.status_code, res.content, res.text, )
415             data = res.text
416             # if self.BodyType == 'json':
417             #     # json格式
418             #     locations = json.loads(data)
419             # else:
420             #     # xml格式
421             #     xtj = xmltojson()
422             #     locations = xtj.main(data)
423             if self.Iflog:
424                 self.log(url, body, data)
425             return data
426         except Exception as error:
427             if self.Iflog:
428                 self.log(url, body, data)
429             return {'172001': '网络错误'}
430 
431     # IVR外呼
432     # @param number  必选参数     待呼叫号码,为Dial节点的属性
433     # @param userdata 可选参数    用户数据,在<startservice>通知中返回,只允许填写数字字符,为Dial节点的属性
434     # @param record   可选参数    是否录音,可填项为true和false,默认值为false不录音,为Dial节点的属性
435 
436     def ivrDial(self, number, userdata, record):
437 
438         self.accAuth()
439         nowdate = datetime.datetime.now()
440         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
441         # 生成sig
442         signature = self.AccountSid + self.AccountToken + self.Batch
443         sig = md5(signature.encode()).hexdigest().upper()
444         # 拼接URL
445         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/ivr/dial?sig=" + sig
446         # 生成auth
447         src = self.AccountSid + ":" + self.Batch
448         auth = base64.encodestring(src.encode()).strip().decode()
449         req = urllib.request.Request(url)
450         req.add_header("Accept", "application/xml")
451         req.add_header("Content-Type", "application/xml;charset=utf-8")
452         req.add_header("Authorization", auth)
453 
454         # 创建包体
455         body = '''<?xml version="1.0" encoding="utf-8"?>
456                 <Request>
457                     <Appid>%s</Appid>
458                     <Dial number="%s"  userdata="%s" record="%s"></Dial>
459                 </Request>
460             ''' % (self.AppId, number, userdata, record)
461         req.data = body
462         data = ''
463         try:
464             # res = urllib.request.urlopen(req)
465             # data = res.read()
466             # res.close()
467             res = requests.post(url, headers=req.headers, data=req.data)
468             # print(res.status_code, res.content, res.text, )
469             data = res.text
470             # xtj = xmltojson()
471             # locations = xtj.main(data)
472             if self.Iflog:
473                 self.log(url, body, data)
474             return data
475         except Exception as error:
476             if self.Iflog:
477                 self.log(url, body, data)
478             return {'172001': '网络错误'}
479 
480     # 话单下载
481     # @param date   必选参数    day 代表前一天的数据(从00:00 – 23:59),目前只支持按天查询
482     # @param keywords  可选参数     客户的查询条件,由客户自行定义并提供给云通讯平台。默认不填忽略此参数
483     def billRecords(self, date, keywords):
484 
485         self.accAuth()
486         nowdate = datetime.datetime.now()
487         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
488         # 生成sig
489         signature = self.AccountSid + self.AccountToken + self.Batch
490         sig = md5(signature.encode()).hexdigest().upper()
491         # 拼接URL
492         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/BillRecords?sig=" + sig
493         # 生成auth
494         src = self.AccountSid + ":" + self.Batch
495         auth = base64.encodestring(src.encode()).strip().decode()
496         req = urllib.request.Request(url)
497         self.setHttpHeader(req)
498         req.add_header("Authorization", auth)
499 
500         # 创建包体
501         body = '''<?xml version="1.0" encoding="utf-8"?><BillRecords>\
502             <appId>%s</appId><date>%s</date><keywords>%s</keywords>\
503             </BillRecords>\
504             ''' % (self.AppId, date, keywords)
505         if self.BodyType == 'json':
506             # if this model is Json ..then do next code
507             body = '''{"appId": "%s", "date": "%s","keywords": "%s"}''' % (self.AppId, date, keywords)
508         req.data = body
509         data = ''
510         try:
511             # res = urllib.request.urlopen(req)
512             # data = res.read()
513             # res.close()
514             res = requests.post(url, headers=req.headers, data=req.data)
515             # print(res.status_code, res.content, res.text, )
516             data = res.text
517 
518             # if self.BodyType == 'json':
519             #     # json格式
520             #     locations = json.loads(data)
521             # else:
522             #     # xml格式
523             #     xtj = xmltojson()
524             #     locations = xtj.main(data)
525             if self.Iflog:
526                 self.log(url, body, data)
527             return data
528         except Exception as error:
529             if self.Iflog:
530                 self.log(url, body, data)
531             return {'172001': '网络错误'}
532 
533     # 主帐号信息查询
534 
535     def queryAccountInfo(self):
536 
537         self.accAuth()
538         nowdate = datetime.datetime.now()
539         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
540         # 生成sig
541         signature = self.AccountSid + self.AccountToken + self.Batch
542         sig = md5(signature.encode()).hexdigest().upper()
543         # 拼接URL
544         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/AccountInfo?sig=" + sig
545         # 生成auth
546         src = self.AccountSid + ":" + self.Batch
547         auth = base64.encodestring(src.encode()).strip().decode()
548         req = urllib.request.Request(url)
549         self.setHttpHeader(req)
550         body = ''
551         req.add_header("Authorization", auth)
552         data = ''
553         try:
554             # res = urllib.request.urlopen(req)
555             # data = res.read()
556             # res.close()
557             res = requests.post(url, headers=req.headers, data=req.data)
558             # print(res.status_code, res.content, res.text, )
559             data = res.text
560             # if self.BodyType == 'json':
561             #     # json格式
562             #     locations = json.loads(data)
563             # else:
564             #     # xml格式
565             #     xtj = xmltojson()
566             #     locations = xtj.main(data)
567             if self.Iflog:
568                 self.log(url, body, data)
569             return data
570         except Exception as error:
571             if self.Iflog:
572                 self.log(url, body, data)
573             return {'172001': '网络错误'}
574 
575     # 短信模板查询
576     # @param templateId  必选参数   模板Id,不带此参数查询全部可用模板
577 
578     def QuerySMSTemplate(self, templateId):
579 
580         self.accAuth()
581         nowdate = datetime.datetime.now()
582         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
583         # 生成sig
584         signature = self.AccountSid + self.AccountToken + self.Batch
585         sig = md5(signature.encode()).hexdigest().upper()
586         # 拼接URL
587         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/SMS/QuerySMSTemplate?sig=" + sig
588         # 生成auth
589         src = self.AccountSid + ":" + self.Batch
590         auth = base64.encodestring(src.encode()).strip().decode()
591         req = urllib.request.Request(url)
592         self.setHttpHeader(req)
593 
594         req.add_header("Authorization", auth)
595 
596         # 创建包体
597         body = '''<?xml version="1.0" encoding="utf-8"?><Request>\
598             <appId>%s</appId><templateId>%s</templateId></Request>
599             ''' % (self.AppId, templateId)
600         if self.BodyType == 'json':
601             # if this model is Json ..then do next code
602             body = '''{"appId": "%s", "templateId": "%s"}''' % (self.AppId, templateId)
603         req.data = body
604         data = ''
605         try:
606             # res = urllib.request.urlopen(req)
607             # data = res.read()
608             # res.close()
609             res = requests.post(url, headers=req.headers, data=req.data)
610             # print(res.status_code, res.content, res.text, )
611             data = res.text
612             # if self.BodyType == 'json':
613             #     # json格式
614             #     locations = json.loads(data)
615             # else:
616             #     # xml格式
617             #     xtj = xmltojson()
618             #     locations = xtj.main2(data)
619             if self.Iflog:
620                 self.log(url, body, data)
621             return data
622         except Exception as error:
623             if self.Iflog:
624                 self.log(url, body, data)
625             return {'172001': '网络错误'}
626 
627     # 呼叫结果查询
628     # @param callsid   必选参数    呼叫ID
629 
630     def CallResult(self, callSid):
631 
632         self.accAuth()
633         nowdate = datetime.datetime.now()
634         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
635         # 生成sig
636         signature = self.AccountSid + self.AccountToken + self.Batch
637         sig = md5(signature.encode()).hexdigest().upper()
638         # 拼接URL
639         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/CallResult?sig=" + sig + "&callsid=" + callSid
640         # 生成auth
641         src = self.AccountSid + ":" + self.Batch
642         auth = base64.encodestring(src.encode()).strip().decode()
643         req = urllib.request.Request(url)
644         self.setHttpHeader(req)
645         body = ''
646         req.add_header("Authorization", auth)
647         data = ''
648         try:
649             # res = urllib.request.urlopen(req)
650             # data = res.read()
651             # res.close()
652             res = requests.post(url, headers=req_headers, data=req_data)
653             # print(res.status_code, res.content, res.text, )
654             data = res.text
655 
656             # if self.BodyType == 'json':
657             #     # json格式
658             #     locations = json.loads(data)
659             # else:
660             #     # xml格式
661             #     xtj = xmltojson()
662             #     locations = xtj.main(data)
663             if self.Iflog:
664                 self.log(url, body, data)
665             return data
666         except Exception as error:
667             if self.Iflog:
668                 self.log(url, body, data)
669             return {'172001': '网络错误'}
670 
671     # 呼叫状态查询
672     # @param callid   必选参数    一个由32个字符组成的电话唯一标识符
673     # @param action      可选参数     查询结果通知的回调url地址
674     def QueryCallState(self, callid, action):
675 
676         self.accAuth()
677         nowdate = datetime.datetime.now()
678         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
679         # 生成sig
680         signature = self.AccountSid + self.AccountToken + self.Batch
681         sig = md5(signature.encode()).hexdigest().upper()
682         # 拼接URL
683         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/ivr/call?sig=" + sig + "&callid=" + callid
684         # 生成auth
685         src = self.AccountSid + ":" + self.Batch
686         auth = base64.encodestring(src.encode()).strip().decode()
687         req = urllib.request.Request(url)
688         self.setHttpHeader(req)
689         req.add_header("Authorization", auth)
690 
691         # 创建包体
692         body = '''<?xml version="1.0" encoding="utf-8"?><Request>\
693             <Appid>%s</Appid><QueryCallState callid="%s" action="%s"/>\
694             </Request>\
695             ''' % (self.AppId, callid, action)
696         if self.BodyType == 'json':
697             # if this model is Json ..then do next code
698             body = '''{"Appid":"%s","QueryCallState":{"callid":"%s","action":"%s"}}''' % (self.AppId, callid, action)
699         req.data = body
700         data = ''
701         try:
702             # res = urllib.request.urlopen(req)
703             # data = res.read()
704             # res.close()
705             res = requests.post(url, headers=req.headers, data=req.data)
706             # print(res.status_code, res.content, res.text, )
707             data = res.text
708 
709             # if self.BodyType == 'json':
710             #     # json格式
711             #     locations = json.loads(data)
712             # else:
713             #     # xml格式
714             #     xtj = xmltojson()
715             #     locations = xtj.main(data)
716             if self.Iflog:
717                 self.log(url, body, data)
718             return data
719         except Exception as error:
720             if self.Iflog:
721                 self.log(url, body, data)
722             return {'172001': '网络错误'}
723 
724     # 语音文件上传
725     # @param filename   必选参数    文件名
726     # @param body      必选参数     二进制串
727     def MediaFileUpload(self, filename, body):
728 
729         self.accAuth()
730         nowdate = datetime.datetime.now()
731         self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
732         # 生成sig
733         signature = self.AccountSid + self.AccountToken + self.Batch
734         sig = md5(signature.encode()).hexdigest().upper()
735         # 拼接URL
736         url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/Calls/MediaFileUpload?sig=" + sig + "&appid=" + self.AppId + "&filename=" + filename
737         # 生成auth
738         src = self.AccountSid + ":" + self.Batch
739         auth = base64.encodestring(src.encode()).strip().decode()
740         req = urllib.request.Request(url)
741         req.add_header("Authorization", auth)
742         if self.BodyType == 'json':
743             req.add_header("Accept", "application/json")
744             req.add_header("Content-Type", "application/octet-stream")
745 
746         else:
747             req.add_header("Accept", "application/xml")
748             req.add_header("Content-Type", "application/octet-stream")
749 
750         # 创建包体
751         req.data = body
752 
753         try:
754             # res = urllib.request.urlopen(req)
755             # data = res.read()
756             # res.close()
757             res = requests.post(url, headers=req.headers, data=req.data)
758             # print(res.status_code, res.content, res.text, )
759             data = res.text
760             # if self.BodyType == 'json':
761             #     # json格式
762             #     locations = json.loads(data)
763             # else:
764             #     # xml格式
765             #     xtj = xmltojson()
766             #     locations = xtj.main(data)
767             if self.Iflog:
768                 self.log(url, body, data)
769             return data
770         except Exception as error:
771             if self.Iflog:
772                 self.log(url, body, data)
773             return {'172001': '网络错误'}
774 
775     # 子帐号鉴权
776     def subAuth(self):
777         if (self.ServerIP == ""):
778             print('172004')
779             print('IP为空')
780 
781         if (self.ServerPort <= 0):
782             print('172005')
783             print('端口错误(小于等于0)')
784 
785         if (self.SoftVersion == ""):
786             print('172013')
787             print('版本号为空')
788 
789         if (self.SubAccountSid == ""):
790             print('172008')
791             print('子帐号为空')
792 
793         if (self.SubAccountToken == ""):
794             print('172009')
795             print('子帐号令牌为空')
796 
797         if (self.AppId == ""):
798             print('172012')
799             print('应用ID为空')
800 
801     # 主帐号鉴权
802     def accAuth(self):
803         if (self.ServerIP == ""):
804             print('172004')
805             print('IP为空')
806 
807         if (int(self.ServerPort) <= 0):
808             print('172005')
809             print('端口错误(小于等于0)')
810 
811         if (self.SoftVersion == ""):
812             print('172013')
813             print('版本号为空')
814 
815         if (self.AccountSid == ""):
816             print('172006')
817             print('主帐号为空')
818 
819         if (self.AccountToken == ""):
820             print('172007')
821             print('主帐号令牌为空')
822 
823         if (self.AppId == ""):
824             print('172012')
825             print('应用ID为空')
826 
827     # 设置包头
828     def setHttpHeader(self, req):
829         if self.BodyType == 'json':
830             req.add_header("Accept", "application/json")
831             req.add_header("Content-Type", "application/json;charset=utf-8")
832 
833         else:
834             req.add_header("Accept", "application/xml")
835             req.add_header("Content-Type", "application/xml;charset=utf-8")
View Code
xmltojson.py
  1 import os
  2 import xml.etree.ElementTree as ET
  3 from xml.dom import minidom
  4 
  5 class xmltojson:
  6     # global var
  7     # show log
  8     SHOW_LOG = True
  9     # XML file
 10     XML_PATH = None
 11     a = {}
 12     m = []
 13 
 14     def get_root(self, path):
 15         '''parse the XML file,and get the tree of the XML file
 16         finally,return the root element of the tree.
 17         if the XML file dose not exist,then print the information'''
 18         # if os.path.exists(path):
 19         # if SHOW_LOG:
 20         # print('start to parse the file : [{}]'.format(path))
 21         tree = ET.fromstring(path)
 22         return tree
 23         # else:
 24         # print('the path [{}] dose not exist!'.format(path))
 25 
 26     def get_element_tag(self, element):
 27         '''return the element tag if the element is not None.'''
 28         if element is not None:
 29 
 30             return element.tag
 31         else:
 32             print('the element is None!')
 33 
 34     def get_element_attrib(self, element):
 35         '''return the element attrib if the element is not None.'''
 36         if element is not None:
 37 
 38             return element.attrib
 39         else:
 40             print('the element is None!')
 41 
 42     def get_element_text(self, element):
 43         '''return the text of the element.'''
 44         if element is not None:
 45             return element.text
 46         else:
 47             print('the element is None!')
 48 
 49     def get_element_children(self, element):
 50         '''return the element children if the element is not None.'''
 51         if element is not None:
 52 
 53             return [c for c in element]
 54         else:
 55             print('the element is None!')
 56 
 57     def get_elements_tag(self, elements):
 58         '''return the list of tags of element's tag'''
 59         if elements is not None:
 60             tags = []
 61             for e in elements:
 62                 tags.append(e.tag)
 63             return tags
 64         else:
 65             print('the elements is None!')
 66 
 67     def get_elements_attrib(self, elements):
 68         '''return the list of attribs of element's attrib'''
 69         if elements is not None:
 70             attribs = []
 71             for a in elements:
 72                 attribs.append(a.attrib)
 73             return attribs
 74         else:
 75             print('the elements is None!')
 76 
 77     def get_elements_text(self, elements):
 78         '''return the dict of element'''
 79         if elements is not None:
 80             text = []
 81             for t in elements:
 82                 text.append(t.text)
 83             return dict(zip(self.get_elements_tag(elements), text))
 84         else:
 85             print('the elements is None!')
 86 
 87     def main(self, xml):
 88         # root
 89         root = self.get_root(xml)
 90 
 91         # children
 92         children = self.get_element_children(root)
 93 
 94         children_tags = self.get_elements_tag(children)
 95 
 96         children_attribs = self.get_elements_attrib(children)
 97 
 98         i = 0
 99 
100         # 获取二级元素的每一个子节点的名称和值
101         for c in children:
102             p = 0
103             c_children = self.get_element_children(c)
104             dict_text = self.get_elements_text(c_children)
105             if dict_text:
106                 # print (children_tags[i])
107                 if children_tags[i] == 'TemplateSMS':
108                     self.a['templateSMS'] = dict_text
109                 else:
110                     if children_tags[i] == 'SubAccount':
111                         k = 0
112 
113                         for x in children:
114                             if children_tags[k] == 'totalCount':
115                                 self.m.append(dict_text)
116                                 self.a['SubAccount'] = self.m
117                                 p = 1
118                             k = k + 1
119                         if p == 0:
120                             self.a[children_tags[i]] = dict_text
121                     else:
122                         self.a[children_tags[i]] = dict_text
123 
124 
125             else:
126                 self.a[children_tags[i]] = c.text
127             i = i + 1
128         return self.a
129 
130     def main2(self, xml):
131         # root
132         root = self.get_root(xml)
133 
134         # children
135         children = self.get_element_children(root)
136 
137         children_tags = self.get_elements_tag(children)
138 
139         children_attribs = self.get_elements_attrib(children)
140 
141         i = 0
142 
143         # 获取二级元素的每一个子节点的名称和值
144         for c in children:
145             p = 0
146             c_children = self.get_element_children(c)
147             dict_text = self.get_elements_text(c_children)
148             if dict_text:
149                 if children_tags[i] == 'TemplateSMS':
150                     k = 0
151 
152                     for x in children:
153                         if children_tags[k] == 'totalCount':
154                             self.m.append(dict_text)
155                             self.a['TemplateSMS'] = self.m
156                             p = 1
157                         k = k + 1
158                     if p == 0:
159                         self.a[children_tags[i]] = dict_text
160                 else:
161                     self.a[children_tags[i]] = dict_text
162 
163             else:
164                 self.a[children_tags[i]] = c.text
165             i = i + 1
166         return self.a
View Code

 

短信验证码运用,和tornado 图形验证码结合使用。例:

register.html

1 <div class="input-group">
2                     <div class="input-group-addon"><i class="fa fa-envelope-o fa-lg fa-fw"></i></div>
3                     <input type="text" class="form-control" name="phonecode" id="phonecode" placeholder="短信验证码" required>
4                     <div class="phonecode input-group-addon">
5                         <a class="phonecode-a" href="javascript:;" onclick="sendSMSCode();">获取验证码</a>
6                     </div>
7                 </div>

register.js

 1 function sendSMSCode() {
 2     $(".phonecode-a").removeAttr("onclick");  //避免连续点击两次时造成两次调用
 3     var mobile = $("#mobile").val();
 4     if (!mobile) {
 5         $("#mobile-err span").html("请填写正确的手机号!");
 6         $("#mobile-err").show();
 7         $(".phonecode-a").attr("onclick", "sendSMSCode();");
 8         return;
 9     } 
10     var imageCode = $("#imagecode").val();
11     if (!imageCode) {
12         $("#image-code-err span").html("请填写验证码!");
13         $("#image-code-err").show();
14         $(".phonecode-a").attr("onclick", "sendSMSCode();");
15         return;
16     }
17 
18     var data = {mobile:mobile, piccode:imageCode, piccode_id:imageCodeId};
19     $.ajax({
20         url: "/api/smscode",
21         method: "POST",
22         data: JSON.stringify(data),
23         contentType: "application/json",
24         dataType: "json",
25         success: function (data) {
26             // data = {
27             //     errcode
28             //     errmsg
29             // }
30             if ("0" == data.errcode) {
31                 var duration = 60;
32                 var timeObj = setInterval(function () {
33                     duration = duration - 1;
34                     $(".phonecode-a").html(duration+"秒");
35                     if (1 == duration) {
36                         clearInterval(timeObj)
37                         $(".phonecode-a").html("获取验证码");
38                         $(".phonecode-a").attr("onclick", "sendSMSCode();")
39                     }
40                 }, 1000, 60)
41             } else {
42                 $("#image-code-err span").html(data.errmsg);
43                 $("#image-code-err").show();
44                 $(".phonecode-a").attr("onclick", "sendSMSCode();")
45                 if (data.errcode == "4002" || data.errcode == "4004") {
46                     generateImageCode();
47                 }
48             }
49         }
50     })

VerifyCode.py

 1 from .BaseHandler import BaseHandler
 2 import logging
 3 import io
 4 import re
 5 import random
 6 
 7 from utils.captcha.captcha import create_validate_code
 8 from constants import *
 9 from utils.response_code import RET
10 from utils.yuntongxun.SendTemplateSMS import ccp
11 
12 """短信验证码"""
13 class SMSCodeHandler(BaseHandler):
14     def post(self):
15         mobile=self.json_args.get("mobile")
16         piccode=self.json_args.get("piccode")
17         piccode_id=self.json_args.get("piccode_id")
18 
19         # 参数校验
20         if not all((mobile,piccode,piccode_id)):
21             return self.write(dict(errcode=RET.PARAMERR,errmsg='参数缺失'))
22         if not re.match(r'^1\d{10}$',mobile):
23             return self.write(dict(errcode=RET.PARAMERR,errmsg='手机号格式错误'))
24 
25         # 获取图片验证码真实值
26         global real_piccode
27         try:
28             real_piccode=self.redis.get("pic_code_%s" % piccode_id)
29         except Exception as e:
30             logging.error(e)
31             self.write(dict(errcode=RET.DBERR,errmsg='查询验证码错误'))
32         if not real_piccode:      #real_piccode要定义为全局变量,不然会报错
33             return self.write(dict(errcode=RET.NODATA, errmsg="验证码过期"))
34 
35         #判断图形验证码正确性
36         if real_piccode.decode('utf-8').lower() != piccode.lower():    ##redis数据real_piccode要解码
37             # print(real_piccode.lower())
38             # print(piccode.lower())
39             return self.write(dict(errcode=RET.DATAERR, errmsg="验证码错误"))
40 
41         #检查手机号码是否存在
42 
43         #生成随机短信验证码
44         sms_code="%04d" %random.randint(0,9999)
45         try:
46             self.redis.setex("sms_code_%s" % mobile, SMS_CODE_EXPIRES_SECONDS, sms_code)
47         except Exception as e:
48             logging.error(e)
49             self.write(dict(errcode=RET.DBERR, errmsg='数据库出错'))
50 
51         #发送短信验证码
52         global result
53         try:
54             result=ccp.sendTemplateSMS(mobile,[sms_code,SMS_CODE_EXPIRES_SECONDS/60],1)
55         except Exception as e:
56             logging.error(e)
57             self.write(dict(errcode=RET.THIRDERR, errmsg='发送短信失败'))
58         if result:
59             self.write(dict(errcode=RET.OK, errmsg='发送成功'))
60         else:
61             self.write(dict(errcode=RET.UNKOWNERR, errmsg='发送失败'))

 

 

 

参考文档:

https://blog.csdn.net/DCclient/article/details/102870028

https://blog.csdn.net/zsx1314lovezyf/article/details/99176682

posted on 2020-04-15 20:19  cherry_ning  阅读(153)  评论(0)    收藏  举报

导航