Exemple #1
0
def weixinlogin():
    api = WeixinAPI(appid=APP_ID,
                    app_secret=APP_SECRET,
                    redirect_uri=REDIRECT_URI)
    authorize_url = api.get_authorize_url(scope=("snsapi_base", ))
    #redirect_uri = api.get_authorize_login_url(scope=("snsapi_login",))
    return redirect(authorize_url)
Exemple #2
0
def login():
    '''获取用户信息'''
    api = WeixinAPI(appid=APP_ID,
                    app_secret=APP_SECRET,
                    redirect_uri=REDIRECT_URI)
    redirect_uri = api.get_authorize_login_url(scope=("snsapi_login",))
    return redirect(redirect_uri)
Exemple #3
0
def login():
	global APP_ID, APP_SECRET, REDIRECT_URI
	api = WeixinAPI(appid=APP_ID,
					app_secret=APP_SECRET,
					redirect_uri=REDIRECT_URI)
	redirect_uri = api.get_authorize_login_url(scope=("snsapi_base",))
	return redirect(redirect_uri)
Exemple #4
0
def weixin_login(request):
    api = WeixinAPI(
        appid=settings.APP_ID,
        app_secret=settings.APP_SECRERT,
        redirect_uri=settings.REDIRECT_URI
    )
    redirect_uri = api.get_authorize_login_url(scope=('snsapi_login',))
    return Response(data=redirect_uri, status=status.HTTP_200_OK)
Exemple #5
0
def authorization():
    code = request.args.get('code')
    api = WeixinAPI(appid=APP_ID,
                    app_secret=APP_SECRET,
                    redirect_uri=REDIRECT_URI)
    auth_info = api.exchange_code_for_access_token(code=code)
    api = WeixinAPI(access_token=auth_info['access_token'])
    resp = api.user(openid=auth_info['openid'])
    return jsonify(resp)
Exemple #6
0
def authorization():
    '''用户验证'''
    code = request.args.get('code')
    api = WeixinAPI(appid=APP_ID,
                    app_secret=APP_SECRET,
                    redirect_uri=REDIRECT_URI)
    auth_info = api.exchange_code_for_access_token(code=code)
    api = WeixinAPI(access_token=auth_info['access_token'])
    resp = api.user(openid=auth_info['openid'])

    with app.test_request_context():
        if check_user(auth_info['openid']):
            requests.post(data=resp)
        else:
            requests.put(data=resp)

    return jsonify(code=0)
Exemple #7
0
class WechatAuth():
    def __init__(self):
        self.PC_api = WeixinAPI(appid = PC_APP_ID,
                                app_secret   = PC_APP_SECRET,
                                redirect_uri = REDIRECT_URL)

        self.Mobile_api = WeixinMpAPI(appid = WX_APP_ID,
                                    app_secret   = WX_APP_SECRET,
                                    redirect_uri = REDIRECT_URL)

        self.pc_auth_url     = self.PC_api.get_authorize_url(scope=(PC_SCOPE,))
        self.mobile_auth_url = self.Mobile_api.get_authorize_url(scope=(WX_SCOPE,))


    def get_authorize_url(self, request):
        if checkMobile(request) == True:
            print self.mobile_auth_url
            return self.mobile_auth_url
        else:
            print self.pc_auth_url
            return self.pc_auth_url

    def get_user(self, request):
        try:
            code = ""
            if request.GET.has_key('code'):
                code = request.GET['code']
            else:
                return None

            if checkMobile(request) == True:
                auth_info = self.Mobile_api.exchange_code_for_access_token(code=code)
                userApi = WeixinMpAPI(access_token=auth_info['access_token'])
                user_info = userApi.user(openid=auth_info['openid'])
                print auth_info, user_info
                return user_info
            else:
                auth_info = self.PC_api.exchange_code_for_access_token(code=code)
                userApi = WeixinAPI(access_token=auth_info['access_token'])
                user_info = userApi.user(openid=auth_info['openid'])
                return user_info
        except Exception, e:
            printError(e)

        return None
Exemple #8
0
    def __init__(self):
        self.PC_api = WeixinAPI(appid = PC_APP_ID,
                                app_secret   = PC_APP_SECRET,
                                redirect_uri = REDIRECT_URL)

        self.Mobile_api = WeixinMpAPI(appid = WX_APP_ID,
                                    app_secret   = WX_APP_SECRET,
                                    redirect_uri = REDIRECT_URL)

        self.pc_auth_url     = self.PC_api.get_authorize_url(scope=(PC_SCOPE,))
        self.mobile_auth_url = self.Mobile_api.get_authorize_url(scope=(WX_SCOPE,))
Exemple #9
0
def authorization(request):
    """
    获取用户信息,登录,跳转
    :param request:
    :return:
    """
    """
    https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx6fe7f0568b75d925&redirect_uri=http://www.yinzishao.cn/authorization&response_type=code&scope=snsapi_userinfo&state=STATE&connect_redirect=1#wechat_redirect
    """
    code = request.GET.get('code')
    auth_redirect_uri = DOMAIN + "authorization"
    api = WeixinAPI(appid=APP_ID,
	    app_secret=APP_SECRET,
	    redirect_uri=auth_redirect_uri)
    auth_info = api.exchange_code_for_access_token(code=code)
    api = WeixinAPI(access_token=auth_info['access_token'])
    resp = api.user(openid=auth_info['openid'])
    request.session['info'] = resp
    openid = resp['openid']

    try:
        user = User.objects.get(username=openid)
    except User.DoesNotExist,e:
        print "user not exist"
        user = User.objects.create_user(openid,password=openid)
def authorization():
    code = request.args.get('code')
    api = WeixinAPI(appid=APP_ID,
                    app_secret=APP_SECRET,
                    redirect_uri=REDIRECT_URI)
    auth_info = api.exchange_code_for_access_token(code=code)
    api = WeixinAPI(access_token=auth_info['access_token'])
    resp = api.user(openid=auth_info['openid'])
    return jsonify(resp)
Exemple #11
0
def weixin_authorization(request):
    code = request.GET.get('code')
    api = WeixinAPI(
        appid=settings.APP_ID,
        app_secret=settings.APP_SECRERT,
        redirect_uri=settings.REDIRECT_URI
    )

    auth_info = api.exchange_code_for_access_token(code=code)
    api = WeixinAPI(access_token=auth_info['access_token'])
    resp = api.user(openid=auth_info['openid'])
    return Response(data=resp, status=status.HTTP_200_OK)
Exemple #12
0
    def get(self, request):
        print(1111111111)
        code = request.GET.get('code')

        print(code)
        api = WeixinAPI(appid="wxbb19e286afae10db",
                        app_secret="064004a0dd2a8a4c0eeed40975e8907c",
                        redirect_uri="http://127.0.0.1:8000/authorization")
        auth_info = api.exchange_code_for_access_token(code=code)
        api = WeixinAPI(access_token=auth_info['access_token'])
        resp = api.user(openid=auth_info['openid'])
        return redirect(
            "http://127.0.0.1:8000/taskpub?nickname={}&headimgurl={}".format(
                resp["nickname"], resp["headimgurl"]))
Exemple #13
0
def adminAuthorization(request):
    """
    获取用户信息,登录,跳转
    :param request:
    :return:
    """
    auth_redirect_uri = DOMAIN + "adminAuthorization"
    code = request.GET.get('code')
    api = WeixinAPI(appid=APP_ID,
	    app_secret=APP_SECRET,
	    redirect_uri=auth_redirect_uri)
    auth_info = api.exchange_code_for_access_token(code=code)
    api = WeixinAPI(access_token=auth_info['access_token'])
    resp = api.user(openid=auth_info['openid'])
    request.session['info'] = resp
    return redirect(DOMAIN + 'administor/view/index.html')
Exemple #14
0
# -*- coding: utf-8 -*-

from weixin.client import WeixinAPI
from weixin.oauth2 import OAuth2AuthExchangeError

APP_ID = 'your app id'
APP_SECRET = 'your secret'
REDIRECT_URI = 'http://www.exmple.com'

code = '0418f2c46cd26e4f9eee5bf03320662M'

api = WeixinAPI(appid=APP_ID, app_secret=APP_SECRET, redirect_uri=REDIRECT_URI)

try:
    pass
    # print api.get_authorize_login_url(scope=("snsapi_login",))
    # print api.exchange_code_for_access_token(code=code)
except OAuth2AuthExchangeError as e:
    print(e)

auth_info = {
    'access_token':
    'OezXcEiiBSKSxW0eoylIeGXVgVFIUy2pK5I7TVatC5MGtVqTIWjtyV5Pax8ZLiWw-NdEN9dPkEX8Yewsve2AktmzS0gmbvzRKO49l6sxHRfhXg1no5ObdGufYhRIubP2m3FUdv-Cop3t3S_xwMbBWQ',
    'refresh_token':
    'OezXcEiiBSKSxW0eoylIeGXVgVFIUy2pK5I7TVatC5MGtVqTIWjtyV5Pax8ZLiWw44bjXRXdmPsclqGIjWs777H3p00QI9a3hzX265Uq9fPJZttNQApdCRPbySXDfofbjniiwsVJiT7fTv7j5jCAxg',
    'openid': u'oV02tuA8Wt6Kk7S0pVydThYvmSJA',
    'expires_in': 7200,
    'scope': u'snsapi_login'
}

try:
Exemple #15
0
class WechatBasic(object):
    """
    微信基本功能类

    仅包含官方 API 中所包含的内容, 如需高级功能支持请移步 ext.py 中的 WechatExt 类
    """
    def __init__(self,
                 token=None,
                 appid=None,
                 appsecret=None,
                 partnerid=None,
                 partnerkey=None,
                 paysignkey=None,
                 access_token=None,
                 access_token_expires_at=None,
                 jsapi_ticket=None,
                 jsapi_ticket_expires_at=None,
                 weixinname=None,
                 firsteye=None,
                 menuMap=None,
                 owner_db=None,
                 open_appid=None,
                 open_secrept=None,
                 open_redirect_uri=None):
        """
        :param token: 微信 Token
        :param appid: App ID
        :param appsecret: App Secret
        :param partnerid: 财付通商户身份标识, 支付权限专用
        :param partnerkey: 财付通商户权限密钥 Key, 支付权限专用
        :param paysignkey: 商户签名密钥 Key, 支付权限专用
        :param access_token: 直接导入的 access_token 值, 该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
        :param access_token_expires_at: 直接导入的 access_token 的过期日期,该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
        :param jsapi_ticket: 直接导入的 jsapi_ticket 值, 该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
        :param jsapi_ticket_expires_at: 直接导入的 jsapi_ticket 的过期日期,该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
        """

        self.__token = token
        self.__token = token
        self.__appid = appid
        self.__appsecret = appsecret
        self.__partnerid = partnerid
        self.__partnerkey = partnerkey
        self.__paysignkey = paysignkey

        self.__access_token = access_token
        self.__access_token_expires_at = access_token_expires_at
        self.__jsapi_ticket = jsapi_ticket
        self.__jsapi_ticket_expires_at = jsapi_ticket_expires_at
        self.__is_parse = False
        self.__message = None
        self.__weixinname = weixinname

        self.owner_db = owner_db

        #实例属性
        self.token = token
        self.appid = appid
        self.open_appid = open_appid
        self.open_secrept = open_secrept
        self.appsecret = appsecret
        self.partnerid = partnerid
        self.partnerkey = partnerkey
        self.paysignkey = paysignkey
        self.firsteye = firsteye
        self.menuMap = menuMap
        self.weixinName = weixinname
        self.open_redirect_uri = open_redirect_uri
        self.openapi = WeixinAPI(appid=self.open_appid,
                                 app_secret=self.open_secrept,
                                 redirect_uri=self.open_redirect_uri)

    def getManager(self, openid=None):
        if openid == None:
            _ret = self.owner_db.query("SELECT * FROM Manager".format(
                self.weixinName))
            ret = []
            for mgr in _ret:
                ret.append(mgr)
        else:
            _ret = self.owner_db.query(
                "SELECT * FROM Manager WHERE openid = '{0}'".format(
                    openid, self.weixinName))
            if len(_ret) > 0:
                ret = _ret[0]
            else:
                ret = None
        return ret

    def getOwOpendid(self, data):
        auth_info = self.openapi.exchange_code_for_access_token(code=data.code)
        user = self.relateUserId(auth_info, "webopenid")
        return user.openid

    def getOpenid(self, data):
        if data.has_key('openid'):
            openid = data.openid
        elif data.has_key("state"):
            if data.state == "pcweb_login":
                openid = self.getOwOpendid(data)
            else:
                openid = self.getWxOpenid(data)
        else:
            openid = "error"
        return openid.encode("utf-8")

    def getWxOpenid(self, data):
        code = data.code
        self._check_appid_appsecret()
        reponse = self._get(
            url="https://api.weixin.qq.com/sns/oauth2/access_token",
            params={
                "grant_type": "authorization_code",
                "appid": self.__appid,
                "secret": self.__appsecret,
                "code": code
            })
        return reponse["openid"]

    def relateUserId(self, user, userid):
        _ret = db.query("SELECT * FROM Customer WHERE unionid='{0}'".format(
            user["unionid"]))
        weixin_user = None
        if len(_ret) == 1:
            weixin_user = _ret[0]
            db.query("UPDATE Customer SET {0} = '{1}' WHERE id={2}".format(
                userid, user['openid'], weixin_user.id))
        return weixin_user

    def getAuth2Url(self, url):
        before = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=" % self.__appid
        after = "&response_type=code&scope=snsapi_base&state=123#wechat_redirect"
        return urllib.unquote(before + url + after)

    def check_signature(self, signature, timestamp, nonce):
        """
        验证微信消息真实性
        :param signature: 微信加密签名
        :param timestamp: 时间戳
        :param nonce: 随机数
        :return: 通过验证返回 True, 未通过验证返回 False
        """
        self._check_token()

        if not signature or not timestamp or not nonce:
            return False

        tmp_list = [self.__token, timestamp, nonce]
        tmp_list.sort()
        tmp_str = ''.join(tmp_list)
        if signature == hashlib.sha1(tmp_str).hexdigest():
            return True
        else:
            return False

    def generate_jsapi_signature(self,
                                 timestamp,
                                 noncestr,
                                 url,
                                 jsapi_ticket=None):
        """
        使用 jsapi_ticket 对 url 进行签名
        :param timestamp: 时间戳
        :param noncestr: 随机数
        :param url: 要签名的 url,不包含 # 及其后面部分
        :param jsapi_ticket: (可选参数) jsapi_ticket 值 (如不提供将自动通过 appid 和 appsecret 获取)
        :return: 返回sha1签名的hexdigest值
        """
        if not jsapi_ticket:
            jsapi_ticket = self.jsapi_ticket
        data = {
            'jsapi_ticket': jsapi_ticket,
            'noncestr': noncestr,
            'timestamp': timestamp,
            'url': url,
        }
        keys = data.keys()
        keys.sort()
        data_str = '&'.join(['%s=%s' % (key, data[key]) for key in keys])
        signature = hashlib.sha1(data_str).hexdigest()
        return signature

    def parse_data(self, data):
        """
        解析微信服务器发送过来的数据并保存类中
        :param data: HTTP Request 的 Body 数据
        :raises ParseError: 解析微信服务器数据错误, 数据不合法
        """
        result = {}
        if type(data) == unicode:
            data = data.encode('utf-8')
        elif type(data) == str:
            pass
        else:
            raise ParseError()

        try:
            doc = minidom.parseString(data)
        except Exception:
            raise ParseError()

        params = [
            ele for ele in doc.childNodes[0].childNodes
            if isinstance(ele, minidom.Element)
        ]

        for param in params:
            if param.childNodes:
                text = param.childNodes[0]
                result[param.tagName] = text.data
        result['raw'] = data
        result['type'] = result.pop('MsgType').lower()

        message_type = MESSAGE_TYPES.get(result['type'], UnknownMessage)
        self.__message = message_type(result)
        self.__is_parse = True

    def get_message(self):
        """
        获取解析好的 WechatMessage 对象
        :return: 解析好的 WechatMessage 对象
        """
        self._check_parse()

        return self.__message

    def get_access_token(self):
        """
        获取 Access Token 及 Access Token 过期日期, 仅供缓存使用, 如果希望得到原生的 Access Token 请求数据请使用 :func:`grant_token`
        :return: dict 对象, key 包括 `access_token` 及 `access_token_expires_at`
        """
        self._check_appid_appsecret()

        return {
            'access_token': self.access_token,
            'access_token_expires_at': self.__access_token_expires_at,
        }

    def get_jsapi_ticket(self):
        """
        获取 Jsapi Ticket 及 Jsapi Ticket 过期日期, 仅供缓存使用, 如果希望得到原生的 Jsapi Ticket 请求数据请使用 :func:`grant_jsapi_ticket`
        :return: dict 对象, key 包括 `jsapi_ticket` 及 `jsapi_ticket_expires_at`
        """
        self._check_appid_appsecret()

        return {
            'jsapi_ticket': self.jsapi_ticket,
            'jsapi_ticket_expires_at': self.__jsapi_ticket_expires_at,
        }

    def response_text(self, content, escape=False):
        """
        将文字信息 content 组装为符合微信服务器要求的响应数据
        :param content: 回复文字
        :param escape: 是否转义该文本内容 (默认不转义)
        :return: 符合微信服务器要求的 XML 响应数据
        """
        self._check_parse()
        content = self._transcoding(content)
        if escape:
            content = cgi.escape(content)

        return TextReply(message=self.__message, content=content).render()

    def response_image(self, media_id):
        """
        将 media_id 所代表的图片组装为符合微信服务器要求的响应数据
        :param media_id: 图片的 MediaID
        :return: 符合微信服务器要求的 XML 响应数据
        """
        self._check_parse()

        return ImageReply(message=self.__message, media_id=media_id).render()

    def response_voice(self, media_id):
        """
        将 media_id 所代表的语音组装为符合微信服务器要求的响应数据
        :param media_id: 语音的 MediaID
        :return: 符合微信服务器要求的 XML 响应数据
        """
        self._check_parse()

        return VoiceReply(message=self.__message, media_id=media_id).render()

    def response_video(self, media_id, title=None, description=None):
        """
        将 media_id 所代表的视频组装为符合微信服务器要求的响应数据
        :param media_id: 视频的 MediaID
        :param title: 视频消息的标题
        :param description: 视频消息的描述
        :return: 符合微信服务器要求的 XML 响应数据
        """
        self._check_parse()
        title = self._transcoding(title)
        description = self._transcoding(description)

        return VideoReply(message=self.__message,
                          media_id=media_id,
                          title=title,
                          description=description).render()

    def response_music(self,
                       music_url,
                       title=None,
                       description=None,
                       hq_music_url=None,
                       thumb_media_id=None):
        """
        将音乐信息组装为符合微信服务器要求的响应数据
        :param music_url: 音乐链接
        :param title: 音乐标题
        :param description: 音乐描述
        :param hq_music_url: 高质量音乐链接, WIFI环境优先使用该链接播放音乐
        :param thumb_media_id: 缩略图的 MediaID
        :return: 符合微信服务器要求的 XML 响应数据
        """
        self._check_parse()
        music_url = self._transcoding(music_url)
        title = self._transcoding(title)
        description = self._transcoding(description)
        hq_music_url = self._transcoding(hq_music_url)

        return MusicReply(message=self.__message,
                          title=title,
                          description=description,
                          music_url=music_url,
                          hq_music_url=hq_music_url,
                          thumb_media_id=thumb_media_id).render()

    def response_news(self, articles):
        """
        将新闻信息组装为符合微信服务器要求的响应数据
        :param articles: list 对象, 每个元素为一个 dict 对象, key 包含 `title`, `description`, `picurl`, `url`
        :return: 符合微信服务器要求的 XML 响应数据
        """
        self._check_parse()
        for article in articles:
            if article.get('title'):
                article['title'] = self._transcoding(article['title'])
            if article.get('description'):
                article['description'] = self._transcoding(
                    article['description'])
            if article.get('picurl'):
                article['picurl'] = self._transcoding(article['picurl'])
            if article.get('url'):
                article['url'] = self._transcoding(article['url'])

        news = ArticleReply(message=self.__message)
        for article in articles:
            article = Article(**article)
            news.add_article(article)
        return news.render()

    def grant_token(self):
        """
        获取 Access Token
        详情请参考 http://mp.weixin.qq.com/wiki/11/0e4b294685f817b95cbed85ba5e82b8f.html
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._get(url="https://api.weixin.qq.com/cgi-bin/token",
                         params={
                             "grant_type": "client_credential",
                             "appid": self.__appid,
                             "secret": self.__appsecret,
                         })

    def grant_jsapi_ticket(self):
        """
        获取 Jsapi Ticket
        详情请参考 http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._get(
            url="https://api.weixin.qq.com/cgi-bin/ticket/getticket",
            params={
                "access_token": self.access_token,
                "type": "jsapi",
            })

    def create_menu(self, menu_data):
        """
        创建自定义菜单 ::

            wechat = WechatBasic(appid='appid', appsecret='appsecret')
            wechat.create_menu({
                'button':[
                    {
                        'type':'click',
                        'name':u'今日歌曲',
                        'key':'V1001_TODAY_MUSIC'
                    },
                    {
                        'type':'click',
                        'name':u'歌手简介',
                        'key':'V1001_TODAY_SINGER'
                    },
                    {
                        'name':u'菜单',
                        'sub_button':[
                            {
                                'type':'view',
                                'name':u'搜索',
                                'url':'http://www.soso.com/'
                            },
                            {
                                'type':'view',
                                'name':u'视频',
                                'url':'http://v.qq.com/'
                            },
                            {
                                'type':'click',
                                'name':u'赞一下我们',
                                'key':'V1001_GOOD'
                            }
                        ]
                    }
                ]})

        详情请参考 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html
        :param menu_data: Python 字典
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._post(url='https://api.weixin.qq.com/cgi-bin/menu/create',
                          data=menu_data)

    def get_menu(self):
        """
        查询自定义菜单
        详情请参考 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._get('https://api.weixin.qq.com/cgi-bin/menu/get')

    def delete_menu(self):
        """
        删除自定义菜单
        详情请参考 http://mp.weixin.qq.com/wiki/16/8ed41ba931e4845844ad6d1eeb8060c8.html
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._get('https://api.weixin.qq.com/cgi-bin/menu/delete')

    def upload_media(self, media_type, media_file, extension=''):
        """
        上传多媒体文件
        详情请参考 http://mp.weixin.qq.com/wiki/10/78b15308b053286e2a66b33f0f0f5fb6.html
        :param media_type: 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
        :param media_file: 要上传的文件,一个 File object 或 StringIO object
        :param extension: 如果 media_file 传入的为 StringIO object,那么必须传入 extension 显示指明该媒体文件扩展名,如 ``mp3``, ``amr``;如果 media_file 传入的为 File object,那么该参数请留空
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()
        if not isinstance(media_file, file) and not isinstance(
                media_file, StringIO):
            raise ValueError(
                'Parameter media_file must be file object or StringIO.StringIO object.'
            )
        if isinstance(media_file, StringIO) and extension.lower() not in [
                'jpg', 'jpeg', 'amr', 'mp3', 'mp4'
        ]:
            raise ValueError(
                'Please provide \'extension\' parameters when the type of \'media_file\' is \'StringIO.StringIO\'.'
            )
        if isinstance(media_file, file):
            extension = media_file.name.split('.')[-1]
            if extension.lower() not in ['jpg', 'jpeg', 'amr', 'mp3', 'mp4']:
                raise ValueError('Invalid file type.')

        ext = {
            'jpg': 'image/jpeg',
            'jpeg': 'image/jpeg',
            'amr': 'audio/amr',
            'mp3': 'audio/mpeg',
            'mp4': 'video/mp4',
        }
        if isinstance(media_file, StringIO):
            filename = 'temp.' + extension
        else:
            filename = media_file.name

        return self._post(
            url='http://file.api.weixin.qq.com/cgi-bin/media/upload',
            params={
                'access_token': self.access_token,
                'type': media_type,
            },
            files={'media': (filename, media_file, ext[extension])})

    def upload_media2(self, media_type, media_file, extension):
        """
        上传多媒体文件
        详情请参考 http://mp.weixin.qq.com/wiki/10/78b15308b053286e2a66b33f0f0f5fb6.html
        :param media_type: 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
        :param media_file: 要上传的文件,一个 File object 或 StringIO object
        :param extension: 如果 media_file 传入的为 StringIO object,那么必须传入 extension 显示指明该媒体文件扩展名,如 ``mp3``, ``amr``;如果 media_file 传入的为 File object,那么该参数请留空
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        #self._check_appid_appsecret()
        #if not isinstance(media_file, str):
        #    raise ValueError('Parameter media_file({0}) must be str object.'.format(type(media_file)))
        #if isinstance(media_file, str) and extension.lower() not in ['jpg', 'jpeg', 'amr', 'mp3', 'mp4']:
        #    raise ValueError('Please provide \'extension\' parameters when the type of \'media_file\' is \'StringIO.StringIO\'.')

        ext = {
            'jpg': 'image/jpeg',
            'jpeg': 'image/jpeg',
            'amr': 'audio/amr',
            'mp3': 'audio/mpeg',
            'mp4': 'video/mp4',
        }
        filename = 'temp.' + extension
        return self._post(
            url='http://file.api.weixin.qq.com/cgi-bin/media/upload',
            params={
                'access_token': self.access_token,
                'type': media_type,
            },
            files={'file': (filename, media_file, ext[extension])})

    def send_template_msg(self, msg):
        """
        第一步:获取模板ID
        通过在模板消息功能的模板库中使用需要的模板,可以获得模板ID。
        第二步:请求接口
        请注意,URL置空,则在发送后,点击模板消息会进入一个空白页面(ios),或无法点击(android)。
        POST请求
            https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
        """
        #print("send_template_msg:{0}".format(msg))
        self._check_appid_appsecret()
        return self._post(
            url=
            'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token='
            + self.access_token,
            data=msg)

    #记录发给用户的消息时间间隔,避免重复的给用户发消息,至少间隔1分钟
    #1分钟间隔 3次
    #10分钟    1次
    #30分钟    1次
    #1小时     1次
    #超过1小时 不再发
    #24小时后 重新开始
    def customser_msg_is_frequent(self,
                                  openid,
                                  cmd,
                                  continue_decide="yes",
                                  minutes_span=1):
        is_frequent = True
        valid_time = datetime.datetime.now() - datetime.timedelta(hours=24)
        _ret = db.query(
            "SELECT * FROM CmdLog WHERE openid='{0}' AND cmd='{1}' AND create_at>'{2}' ORDER BY create_at DESC"
            .format(openid, cmd, valid_time))

        if len(_ret) == 0:
            is_frequent = False
        else:
            cmd_num = len(_ret)
            cmd_log = _ret[0]
            min_span = (datetime.datetime.now() -
                        cmd_log.create_at).total_seconds() / 60.0
            if continue_decide == "yes":
                if cmd_num <= 2:
                    is_frequent = (True if min_span < minutes_span else False)
                elif cmd_num == 3:
                    is_frequent = (True
                                   if min_span < minutes_span * 10 else False)
                elif cmd_num == 4:
                    is_frequent = (True
                                   if min_span < minutes_span * 30 else False)
                elif cmd_num == 5:
                    is_frequent = (True
                                   if min_span < minutes_span * 60 else False)
                else:
                    is_frequent = True
            else:
                if min_span > minutes_span:
                    is_frequent = False
                else:
                    is_frequent = True
        if is_frequent == False:
            _ret = db.insert("CmdLog",
                             openid=openid,
                             cmd=cmd,
                             create_at=datetime.datetime.now())

        return is_frequent

    def send_customer_text_msg(self, openid, msg, customservice=None):
        self._check_appid_appsecret()
        params = {
            "touser": openid,
            "msgtype": "text",
            "text": {
                "content": msg
            }
        }
        if customservice is not None:
            params["customservice"] = {"kf_account": customservice}
        return self._post(
            url=
            'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='
            + self.access_token,
            data=params)

    def send_customer_voice_msg(self, openid, media_id, customservice=None):
        self._check_appid_appsecret()
        params = {
            "touser": openid,
            "msgtype": "voice",
            "voice": {
                "media_id": media_id
            }
        }
        if customservice is not None:
            params["customservice"] = {"kf_account": customservice}
        return self._post(
            url=
            'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='
            + self.access_token,
            data=params)

    def send_customer_image_msg(self, openid, media_id, customservice=None):
        self._check_appid_appsecret()
        params = {
            "touser": openid,
            "msgtype": "image",
            "image": {
                "media_id": media_id
            }
        }
        if customservice is not None:
            params["customservice"] = {"kf_account": customservice}
        return self._post(
            url=
            'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='
            + self.access_token,
            data=params)

    def send_customer_video_msg(self,
                                openid,
                                title,
                                media_id,
                                thumb_media_id,
                                description,
                                customservice=None):
        self._check_appid_appsecret()
        params = {
            "touser": openid,
            "msgtype": "video",
            "video": {
                "media_id": media_id,
                "thumb_media_id": thumb_media_id,
                "title": title,
                "description": description
            }
        }
        if customservice is not None:
            params["customservice"] = {"kf_account": customservice}
        return self._post(
            url=
            'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='
            + self.access_token,
            data=params)

    def send_customer_music_msg(self,
                                openid,
                                title,
                                music_url,
                                hq_music_url,
                                thumb_media_id,
                                description,
                                customservice=None):
        self._check_appid_appsecret()
        params = {
            "touser": openid,
            "msgtype": "music",
            "music": {
                "title": title,
                "description": description,
                "musicurl": music_url,
                "hqmusicurl": hq_music_url,
                "thumb_media_id": thumb_media_id
            }
        }
        if customservice is not None:
            params["customservice"] = {"kf_account": customservice}
        return self._post(
            url=
            'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='
            + self.access_token,
            data=params)

    #发送图文消息 图文消息条数限制在10条以内,注意,如果图文数超过10,则将会无响应。
    #{
    #    "touser":"******",
    #    "msgtype":"news",
    #    "news":{
    #        "articles": [
    #        {
    #            "title":"Happy Day",
    #            "description":"Is Really A Happy Day",
    #            "url":"URL",
    #            "picurl":"PIC_URL"
    #        },
    #        {
    #            "title":"Happy Day",
    #            "description":"Is Really A Happy Day",
    #            "url":"URL",
    #            "picurl":"PIC_URL"
    #        }
    #        ]
    #    }
    #}
    def send_customer_news_msg(self, openid, news, customservice=None):
        self._check_appid_appsecret()
        params = {
            "touser": openid,
            "msgtype": "news",
            "news": {
                "articles": news
            }
        }
        if customservice is not None:
            params["customservice"] = {"kf_account": customservice}
        return self._post(
            url=
            'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='
            + self.access_token,
            data=params)

    def download_media(self, media_id):
        """
        下载多媒体文件
        详情请参考 http://mp.weixin.qq.com/wiki/10/78b15308b053286e2a66b33f0f0f5fb6.html
        :param media_id: 媒体文件 ID
        :return: requests 的 Response 实例
        """
        self._check_appid_appsecret()
        with closing(
                requests.get(
                    'http://file.api.weixin.qq.com/cgi-bin/media/get',
                    params={
                        'access_token': self.access_token,
                        'media_id': media_id,
                    },
                    stream=True,
                )) as r:
            ret = r.content

        return ret

    def download_media2file(self, media_id, file_name):
        content = self.download_media(media_id)
        WriteFileData = open(file_name, 'wb')
        WriteFileData.write(content)
        WriteFileData.close()
        return

    def create_group(self, name):
        """
        创建分组
        详情请参考 http://mp.weixin.qq.com/wiki/13/be5272dc4930300ba561d927aead2569.html
        :param name: 分组名字(30个字符以内)
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/groups/create',
            data={
                'group': {
                    'name': name,
                },
            })

    def get_groups(self):
        """
        查询所有分组
        详情请参考 http://mp.weixin.qq.com/wiki/13/be5272dc4930300ba561d927aead2569.html
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._get('https://api.weixin.qq.com/cgi-bin/groups/get')

    def get_group_by_id(self, openid):
        """
        查询用户所在分组
        详情请参考 http://mp.weixin.qq.com/wiki/13/be5272dc4930300ba561d927aead2569.html
        :param openid: 用户的OpenID
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._post(url='https://api.weixin.qq.com/cgi-bin/groups/getid',
                          data={
                              'openid': openid,
                          })

    def update_group(self, group_id, name):
        """
        修改分组名
        详情请参考 http://mp.weixin.qq.com/wiki/13/be5272dc4930300ba561d927aead2569.html
        :param group_id: 分组id,由微信分配
        :param name: 分组名字(30个字符以内)
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/groups/update',
            data={'group': {
                'id': int(group_id),
                'name': name,
            }})

    def move_user(self, user_id, group_id):
        """
        移动用户分组
        详情请参考 http://mp.weixin.qq.com/wiki/13/be5272dc4930300ba561d927aead2569.html
        :param user_id: 用户 ID 。 就是你收到的 WechatMessage 的 source
        :param group_id: 分组 ID
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/groups/members/update',
            data={
                'openid': user_id,
                'to_groupid': group_id,
            })

    #内部数据库中获取用户信息
    def get_user_info2(self, openid, format="orign"):
        _ret = self.owner_db.query(
            "SELECT * FROM Customer WHERE openid = '{0}'".format(openid))
        if len(_ret) > 0:
            user = _ret[0]
            if (user.upload_time is None) or (
                (datetime.datetime.now() - user.upload_time).total_seconds() >
                    10 * 24 * 60 * 60):  #大于10天,重新刷新一下用户信息
                user = self.update_user_info(openid)
        else:
            user = self.update_user_info(openid)

        ret = {}
        for key in user:
            if format == "orign":
                ret[key] = user[key]
            else:
                ret[key] = user[key].strftime(
                    "%Y-%m-%d %H:%M:%S") if isinstance(
                        user[key], datetime.datetime) else user[key]
        return ret

    def get_user_info(self, user_id, lang='zh_CN'):
        """
        获取用户基本信息
        详情请参考 http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html
        :param user_id: 用户 ID, 就是你收到的 WechatMessage 的 source
        :param lang: 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._get(url='https://api.weixin.qq.com/cgi-bin/user/info',
                         params={
                             'access_token': self.access_token,
                             'openid': user_id,
                             'lang': lang,
                         })

    def update_user_info(self, openid):
        user = self.get_user_info(openid)
        _ret = self.owner_db.query(
            "SELECT * FROM Customer WHERE openid='{0}'".format(openid))
        if user.has_key("subscribe_time"):  #关注或者已经关注
            if len(_ret) == 0:
                self.owner_db.insert(
                    "Customer",
                    openid=openid,
                    unionid=user['unionid'],
                    subscribe_at=datetime.datetime.fromtimestamp(
                        user["subscribe_time"]).strftime("%Y-%m-%d %H:%M:%S"),
                    nickname=user['nickname'],
                    city=user['city'],
                    province=user['province'],
                    country=user['country'],
                    headimgurl=user['headimgurl'],
                    groupid=user['groupid'],
                    upload_time=datetime.datetime.now(),
                )
            else:
                self.owner_db.update(
                    "Customer",
                    where='openid=$openid',
                    vars=locals(),
                    unionid=user['unionid'],
                    subscribe_at=datetime.datetime.fromtimestamp(
                        user["subscribe_time"]).strftime("%Y-%m-%d %H:%M:%S"),
                    weixinname=self.weixinName,
                    nickname=user['nickname'],
                    city=user['city'],
                    province=user['province'],
                    country=user['country'],
                    headimgurl=user['headimgurl'],
                    groupid=user['groupid'],
                    upload_time=datetime.datetime.now(),
                )
        elif len(_ret) > 0:  #是不关注事件

            self.owner_db.update("Customer",
                                 where='openid=$openid',
                                 vars=locals(),
                                 unsubscribe_at=datetime.datetime.now())
        _ret = self.owner_db.query(
            "SELECT * FROM Customer WHERE openid = '{0}' ".format(openid))
        ret = None if len(_ret) == 0 else _ret[0]
        return ret

    def get_followers(self, first_user_id=None):
        """
        获取关注者列表
        详情请参考 http://mp.weixin.qq.com/wiki/3/17e6919a39c1c53555185907acf70093.html
        :param first_user_id: 可选。第一个拉取的OPENID,不填默认从头开始拉取
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        params = {
            'access_token': self.access_token,
        }
        if first_user_id:
            params['next_openid'] = first_user_id
        return self._get('https://api.weixin.qq.com/cgi-bin/user/get',
                         params=params)

    def send_text_message(self, user_id, content):
        """
        发送文本消息
        详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html
        :param user_id: 用户 ID, 就是你收到的 WechatMessage 的 source
        :param content: 消息正文
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/message/custom/send',
            data={
                'touser': user_id,
                'msgtype': 'text',
                'text': {
                    'content': content,
                },
            })

    def send_image_message(self, user_id, media_id):
        """
        发送图片消息
        详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html
        :param user_id: 用户 ID, 就是你收到的 WechatMessage 的 source
        :param media_id: 图片的媒体ID。 可以通过 :func:`upload_media` 上传。
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/message/custom/send',
            data={
                'touser': user_id,
                'msgtype': 'image',
                'image': {
                    'media_id': media_id,
                },
            })

    def send_voice_message(self, user_id, media_id):
        """
        发送语音消息
        详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html
        :param user_id: 用户 ID, 就是你收到的 WechatMessage 的 source
        :param media_id: 发送的语音的媒体ID。 可以通过 :func:`upload_media` 上传。
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/message/custom/send',
            data={
                'touser': user_id,
                'msgtype': 'voice',
                'voice': {
                    'media_id': media_id,
                },
            })

    def send_video_message(self,
                           user_id,
                           media_id,
                           title=None,
                           description=None):
        """
        发送视频消息
        详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html
        :param user_id: 用户 ID, 就是你收到的 WechatMessage 的 source
        :param media_id: 发送的视频的媒体ID。 可以通过 :func:`upload_media` 上传。
        :param title: 视频消息的标题
        :param description: 视频消息的描述
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        video_data = {
            'media_id': media_id,
        }
        if title:
            video_data['title'] = title
        if description:
            video_data['description'] = description

        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/message/custom/send',
            data={
                'touser': user_id,
                'msgtype': 'video',
                'video': video_data,
            })

    def send_music_message(self,
                           user_id,
                           url,
                           hq_url,
                           thumb_media_id,
                           title=None,
                           description=None):
        """
        发送音乐消息
        详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html
        :param user_id: 用户 ID, 就是你收到的 WechatMessage 的 source
        :param url: 音乐链接
        :param hq_url: 高品质音乐链接,wifi环境优先使用该链接播放音乐
        :param thumb_media_id: 缩略图的媒体ID。 可以通过 :func:`upload_media` 上传。
        :param title: 音乐标题
        :param description: 音乐描述
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        music_data = {
            'musicurl': url,
            'hqmusicurl': hq_url,
            'thumb_media_id': thumb_media_id,
        }
        if title:
            music_data['title'] = title
        if description:
            music_data['description'] = description

        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/message/custom/send',
            data={
                'touser': user_id,
                'msgtype': 'music',
                'music': music_data,
            })

    def send_article_message(self, user_id, articles):
        """
        发送图文消息
        详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html
        :param user_id: 用户 ID, 就是你收到的 WechatMessage 的 source
        :param articles: list 对象, 每个元素为一个 dict 对象, key 包含 `title`, `description`, `picurl`, `url`
        :return: 返回的 JSON 数据包
        """
        self._check_appid_appsecret()

        articles_data = []
        for article in articles:
            article = Article(**article)
            articles_data.append({
                'title': article.title,
                'description': article.description,
                'url': article.url,
                'picurl': article.picurl,
            })
        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/message/custom/send',
            data={
                'touser': user_id,
                'msgtype': 'news',
                'news': {
                    'articles': articles_data,
                },
            })

    def _genQRCode(self, info, file_name):
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=10,
            border=4,
        )
        qr.add_data(info)
        qr.make(fit=True)
        img = qr.make_image()
        img.save(file_name, 'JPEG')
        return

    #创建二维码,并保存到文件
    def create_temp_qrcode2(self, scene_id, file_name, expire_seconds=604800):
        ret = self.create_temp_qrcode(scene_id, expire_seconds)
        self._genQRCode(ret["url"], file_name)

    def create_temp_qrcode(self, scene_id, expire_seconds=604800):
        """
        创建二维码
        详情请参考 http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html
        :param data: 你要发送的参数 dict
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()
        data = {
            "access_token": self.access_token,
            "expire_seconds": expire_seconds,
            "action_name": "QR_SCENE",
            "action_info": {
                "scene": {
                    "scene_id": scene_id
                }
            }
        }
        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/qrcode/create', data=data)

    #创建二维码,并保存到文件
    def create_perm_qrcode2(self, scene_str, qrcode_url, file_name):
        ret = self.create_perm_qrcode(scene_str)
        orgUrl = ret["url"]
        #创建二维码
        self._genQRCode(orgUrl, file_name)
        #是永久二维码,还需要计入数据库,进行备案
        db.update("WeixinQRcodeScene",
                  where="qrcode_url=$qrcode_url",
                  url=orgUrl,
                  vars=locals())

    def create_perm_qrcode(self, scene_str):
        """
        创建二维码
        详情请参考 http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html
        :param data: 你要发送的参数 dict
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        data = {"access_token": self.access_token}
        if (type(scene_str) is str):  #字符串类型scene_id
            data["action_name"] = "QR_LIMIT_STR_SCENE"
            data["action_info"] = {"scene": {"scene_str": scene_str}}
        else:  #整数类型scene_id
            data["action_name"] = "QR_LIMIT_SCENE"
            data["action_info"] = {"scene": {"scene_id": scene_str}}
        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/qrcode/create', data=data)

    def create_qrcode(self, **data):
        """
        创建二维码
        详情请参考 http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html
        :param data: 你要发送的参数 dict
        :return: 返回的 JSON 数据包
        :raise HTTPError: 微信api http 请求失败
        """
        self._check_appid_appsecret()

        return self._post(
            url='https://api.weixin.qq.com/cgi-bin/qrcode/create', data=data)

    def show_qrcode(self, ticket):
        """
        通过ticket换取二维码
        详情请参考 http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html
        :param ticket: 二维码 ticket 。可以通过 :func:`create_qrcode` 获取到
        :return: 返回的 Request 对象
        """
        self._check_appid_appsecret()

        return requests.get(url='https://mp.weixin.qq.com/cgi-bin/showqrcode',
                            params={'ticket': ticket})

    def markOuttimeWeixinPara(self):
        for key in ['access_token', 'jsapi_ticket']:
            #检查access_token 是否过期
            _ret = db.query(
                "SELECT * FROM GlobalPara WHERE  name='{0}'".format(key))
            for token in _ret:
                now = time.time()
                if token.expired_at - now < 300:
                    db.query("DELETE FROM GlobalPara WHERE id = {0}".format(
                        token.id))

    def get_jdk_sign(self, url):
        #处理url中#字符情况
        temp = url.split("#")[0]
        ret = {
            'nonceStr': self.__create_nonce_str(),
            'jsapi_ticket': self.jsapi_ticket,
            'timestamp': self.__create_timestamp(),
            'url': temp
        }
        string = '&'.join(
            ['%s=%s' % (key.lower(), ret[key]) for key in sorted(ret)])
        ret['signature'] = hashlib.sha1(string).hexdigest()
        ret['appid'] = self.__appid
        ret['url'] = url
        return ret

    def get_pay_sign(self, prepay_id):
        ret = {
            'appId': self.__appid,
            'timestamp': self.__create_timestamp(),
            'nonceStr': self.__create_nonce_str(),
            'package': 'prepay_id={0}'.format(prepay_id),
            'signType': 'MD5',
        }
        string = '&'.join(
            ['%s=%s' % (key.lower(), ret[key]) for key in sorted(ret)])
        ret['paySign'] = hashlib.sha1(string).hexdigest().upper()
        if test:
            ret['string'] = string
        return ret

    @property
    def access_token(self):
        self._check_appid_appsecret()
        #来自上次查询的token
        _ret = db.query(
            "SELECT * FROM GlobalPara WHERE owner='{0}' AND name='access_token' ORDER BY create_at DESC LIMIT 0,3"
            .format(self.__weixinname))
        if len(_ret) >= 1:
            self.__access_token = _ret[0].value.encode('utf-8')
            return self.__access_token

        #if self.__access_token:
        #    now = time.time()
        #    if self.__access_token_expires_at - now > 60:
        #        return self.__access_token
        response_json = self.grant_token()

        self.__access_token = response_json['access_token']
        #self.__access_token_expires_at = int(time.time()) + response_json['expires_in'] - 60*60
        self.__access_token_expires_at = int(time.time()) + 20 * 60
        db.insert("GlobalPara",
                  name='access_token',
                  owner=self.__weixinname,
                  value=self.__access_token,
                  create_at=datetime.datetime.now(),
                  expired_at=self.__access_token_expires_at)
        return self.__access_token

    @property
    def jsapi_ticket(self):
        self._check_appid_appsecret()
        #如果数据库中有数据,则认为有效
        _ret = db.query(
            "SELECT * FROM GlobalPara WHERE owner='{0}' AND name='jsapi_ticket' ORDER BY create_at DESC LIMIT 0,3"
            .format(self.__weixinname))
        if len(_ret) >= 1:
            self.__jsapi_ticket = _ret[0].value.encode('utf-8')
            return self.__jsapi_ticket

        #if self.__jsapi_ticket:
        #   now = time.time()
        #   if self.__jsapi_ticket_expires_at - now > 60:
        #       return self.__jsapi_ticket
        response_json = self.grant_jsapi_ticket()
        self.__jsapi_ticket = response_json['ticket'].encode("utf-8")
        self.__jsapi_ticket_expires_at = int(
            time.time()) + response_json['expires_in'] - 300
        #将新生成的ticket值入库
        db.insert("GlobalPara",
                  name='jsapi_ticket',
                  owner=self.__weixinname,
                  value=self.__jsapi_ticket,
                  create_at=datetime.datetime.now(),
                  expired_at=self.__jsapi_ticket_expires_at)
        return self.__jsapi_ticket

    def _check_token(self):
        """
        检查 Token 是否存在
        :raises NeedParamError: Token 参数没有在初始化的时候提供
        """
        if not self.__token:
            raise NeedParamError(
                'Please provide Token parameter in the construction of class.')

    def _check_appid_appsecret(self):
        """
        检查 AppID 和 AppSecret 是否存在
        :raises NeedParamError: AppID 或 AppSecret 参数没有在初始化的时候完整提供
        """
        if not self.__appid or not self.__appsecret:
            raise NeedParamError(
                'Please provide app_id and app_secret parameters in the construction of class.'
            )

    def _check_parse(self):
        """
        检查是否成功解析微信服务器传来的数据
        :raises NeedParseError: 需要解析微信服务器传来的数据
        """
        if not self.__is_parse:
            raise NeedParseError()

    def _check_official_error(self, json_data, times=0):
        """
        检测微信公众平台返回值中是否包含错误的返回码
        :raises OfficialAPIError: 如果返回码提示有错误,抛出异常;否则返回 True
        """
        if "errcode" in json_data and json_data["errcode"] != 0:
            #删除过期access_token,jsapi_ticket值
            db.query(
                "DELETE FROM GlobalPara WHERE owner='{0}' AND (name='jsapi_ticket' OR name='access_token')"
                .format(self.__weixinname))
            raise OfficialAPIError("{}: {}".format(json_data["errcode"],
                                                   json_data["errmsg"]))

    def _request(self, method, url, **kwargs):
        """
        向微信服务器发送请求
        :param method: 请求方法
        :param url: 请求地址
        :param kwargs: 附加数据
        :return: 微信服务器响应的 json 数据
        :raise HTTPError: 微信api http 请求失败
        """
        if "params" not in kwargs:
            kwargs["params"] = {
                "access_token": self.access_token,
            }
        if isinstance(kwargs.get("data", ""), dict):
            body = json.dumps(kwargs["data"], ensure_ascii=False)
            body = body.encode('utf8')
            kwargs["data"] = body

        r = requests.request(method=method, url=url, **kwargs)
        r.raise_for_status()
        response_json = r.json()
        self._check_official_error(response_json)
        return response_json

    def _get(self, url, **kwargs):
        """
        使用 GET 方法向微信服务器发出请求
        :param url: 请求地址
        :param kwargs: 附加数据
        :return: 微信服务器响应的 json 数据
        :raise HTTPError: 微信api http 请求失败
        """
        return self._request(method="get", url=url, **kwargs)

    def _post(self, url, **kwargs):
        """
        使用 POST 方法向微信服务器发出请求
        :param url: 请求地址
        :param kwargs: 附加数据
        :return: 微信服务器响应的 json 数据
        :raise HTTPError: 微信api http 请求失败
        """
        return self._request(method="post", url=url, **kwargs)

    def _transcoding(self, data):
        """
        编码转换
        :param data: 需要转换的数据
        :return: 转换好的数据
        """
        if not data:
            return data

        result = None
        if type(data) == unicode:
            result = data
        elif type(data) == str:
            result = data.decode('utf-8')
        else:
            raise ParseError()
        return result

    def __create_nonce_str(self):
        nonce_str = ''.join(
            random.choice(string.ascii_letters + string.digits)
            for _ in range(15))
        return nonce_str

    def __create_timestamp(self):
        stamp = int(time.time())
        return stamp
 def getUrl(url):
     WechatUser.api = WeixinAPI(appid=WechatUser.APP_ID, app_secret=WechatUser.APP_SECRET, redirect_uri=url)
     return WechatUser.api.get_authorize_url(scope=WechatUser.scope)
 def getUserInfo(code):
     auth_info = WechatUser.api.exchange_code_for_access_token(code=code)
     data = WeixinAPI(access_token=auth_info['access_token'])
     return data.user(openid=auth_info['openid'])
try:
    import __builtin__
    input = getattr(__builtin__, 'raw_input')
except (ImportError, AttributeError):
    pass


appid = input("App ID: ").strip()
app_secret = input("App Secret: ").strip()
redirect_uri = input("Redirect URI: ").strip()
raw_scope = input("Requested scope (separated by spaces, blank for just basic read): ").strip()
scope = raw_scope.split(' ')
# For basic, API seems to need to be set explicitly
if not scope or scope == [""]:
    scope = ["snsapi_login"]


api = WeixinAPI(appid=appid,
                app_secret=app_secret,
                redirect_uri=redirect_uri)
redirect_uri = api.get_authorize_login_url(scope=scope)

print ("Visit this page and authorize access in your browser: "+ redirect_uri)

code = (str(input("Paste in code in query string after redirect: ").strip()))

access_token = api.exchange_code_for_access_token(code)

print ("access token: " )
print (access_token)
Exemple #19
0
# -*- coding: utf-8 -*-


from weixin.client import WeixinAPI
from weixin.oauth2 import OAuth2AuthExchangeError

APP_ID = 'your app id'
APP_SECRET = 'your secret'
REDIRECT_URI = 'http://www.exmple.com'


code = '0418f2c46cd26e4f9eee5bf03320662M'

api = WeixinAPI(appid=APP_ID,
                app_secret=APP_SECRET,
                redirect_uri=REDIRECT_URI)

try:
    pass
    # print api.get_authorize_login_url(scope=("snsapi_login",))
    # print api.exchange_code_for_access_token(code=code)
except OAuth2AuthExchangeError, e:
    print e


auth_info = {
    'access_token': 'OezXcEiiBSKSxW0eoylIeGXVgVFIUy2pK5I7TVatC5MGtVqTIWjtyV5Pax8ZLiWw-NdEN9dPkEX8Yewsve2AktmzS0gmbvzRKO49l6sxHRfhXg1no5ObdGufYhRIubP2m3FUdv-Cop3t3S_xwMbBWQ',
    'refresh_token': 'OezXcEiiBSKSxW0eoylIeGXVgVFIUy2pK5I7TVatC5MGtVqTIWjtyV5Pax8ZLiWw44bjXRXdmPsclqGIjWs777H3p00QI9a3hzX265Uq9fPJZttNQApdCRPbySXDfofbjniiwsVJiT7fTv7j5jCAxg',
    'openid': u'oV02tuA8Wt6Kk7S0pVydThYvmSJA',
    'expires_in': 7200,
    'scope': u'snsapi_login'}
Exemple #20
0
# -*- coding: utf-8 -*-

from weixin.client import WeixinAPI
from weixin.oauth2 import OAuth2AuthExchangeError

APP_ID = 'wxbdc5610cc59c1631'
APP_SECRET = 'your app secret'
REDIRECT_URI = 'https://passport.yhd.com/wechat/callback.do'

code = '021b66a31b7179822b01e7e2c12528cV'

api = WeixinAPI(appid=APP_ID, app_secret=APP_SECRET, redirect_uri=REDIRECT_URI)

try:
    print(api.get_authorize_login_url(scope=("snsapi_login", )))
    print(api.exchange_code_for_access_token(code=code))
except OAuth2AuthExchangeError as e:
    print(e)

auth_info = {
    'access_token':
    'OezXcEiiBSKSxW0eoylIeGXVgVFIUy2pK5I7TVatC5MGtVqTIWjtyV5Pax8ZLiWw-NdEN9dPkEX8Yewsve2AktmzS0gmbvzRKO49l6sxHRfhXg1no5ObdGufYhRIubP2m3FUdv-Cop3t3S_xwMbBWQ',
    'refresh_token':
    'OezXcEiiBSKSxW0eoylIeGXVgVFIUy2pK5I7TVatC5MGtVqTIWjtyV5Pax8ZLiWw44bjXRXdmPsclqGIjWs777H3p00QI9a3hzX265Uq9fPJZttNQApdCRPbySXDfofbjniiwsVJiT7fTv7j5jCAxg',
    'openid': u'oV02tuA8Wt6Kk7S0pVydThYvmSJA',
    'expires_in': 7200,
    'scope': u'snsapi_login'
}

print(
    api.exchange_refresh_token_for_access_token(
Exemple #21
0
# -*- coding: utf-8 -*-


from weixin.client import WeixinAPI
from weixin.oauth2 import OAuth2AuthExchangeError

APP_ID = "wxbdc5610cc59c1631"
APP_SECRET = "your app secret"
REDIRECT_URI = "https://passport.yhd.com/wechat/callback.do"


code = "021b66a31b7179822b01e7e2c12528cV"

api = WeixinAPI(appid=APP_ID, app_secret=APP_SECRET, redirect_uri=REDIRECT_URI)

try:
    print api.get_authorize_login_url(scope=("snsapi_login",))
    print api.exchange_code_for_access_token(code=code)
except OAuth2AuthExchangeError, e:
    print e

auth_info = {
    "access_token": "OezXcEiiBSKSxW0eoylIeGXVgVFIUy2pK5I7TVatC5MGtVqTIWjtyV5Pax8ZLiWw-NdEN9dPkEX8Yewsve2AktmzS0gmbvzRKO49l6sxHRfhXg1no5ObdGufYhRIubP2m3FUdv-Cop3t3S_xwMbBWQ",
    "refresh_token": "OezXcEiiBSKSxW0eoylIeGXVgVFIUy2pK5I7TVatC5MGtVqTIWjtyV5Pax8ZLiWw44bjXRXdmPsclqGIjWs777H3p00QI9a3hzX265Uq9fPJZttNQApdCRPbySXDfofbjniiwsVJiT7fTv7j5jCAxg",
    "openid": u"oV02tuA8Wt6Kk7S0pVydThYvmSJA",
    "expires_in": 7200,
    "scope": u"snsapi_login",
}

print api.exchange_refresh_token_for_access_token(refresh_token=auth_info["refresh_token"])
Exemple #22
0
    def __init__(self,
                 token=None,
                 appid=None,
                 appsecret=None,
                 partnerid=None,
                 partnerkey=None,
                 paysignkey=None,
                 access_token=None,
                 access_token_expires_at=None,
                 jsapi_ticket=None,
                 jsapi_ticket_expires_at=None,
                 weixinname=None,
                 firsteye=None,
                 menuMap=None,
                 owner_db=None,
                 open_appid=None,
                 open_secrept=None,
                 open_redirect_uri=None):
        """
        :param token: 微信 Token
        :param appid: App ID
        :param appsecret: App Secret
        :param partnerid: 财付通商户身份标识, 支付权限专用
        :param partnerkey: 财付通商户权限密钥 Key, 支付权限专用
        :param paysignkey: 商户签名密钥 Key, 支付权限专用
        :param access_token: 直接导入的 access_token 值, 该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
        :param access_token_expires_at: 直接导入的 access_token 的过期日期,该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
        :param jsapi_ticket: 直接导入的 jsapi_ticket 值, 该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
        :param jsapi_ticket_expires_at: 直接导入的 jsapi_ticket 的过期日期,该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
        """

        self.__token = token
        self.__token = token
        self.__appid = appid
        self.__appsecret = appsecret
        self.__partnerid = partnerid
        self.__partnerkey = partnerkey
        self.__paysignkey = paysignkey

        self.__access_token = access_token
        self.__access_token_expires_at = access_token_expires_at
        self.__jsapi_ticket = jsapi_ticket
        self.__jsapi_ticket_expires_at = jsapi_ticket_expires_at
        self.__is_parse = False
        self.__message = None
        self.__weixinname = weixinname

        self.owner_db = owner_db

        #实例属性
        self.token = token
        self.appid = appid
        self.open_appid = open_appid
        self.open_secrept = open_secrept
        self.appsecret = appsecret
        self.partnerid = partnerid
        self.partnerkey = partnerkey
        self.paysignkey = paysignkey
        self.firsteye = firsteye
        self.menuMap = menuMap
        self.weixinName = weixinname
        self.open_redirect_uri = open_redirect_uri
        self.openapi = WeixinAPI(appid=self.open_appid,
                                 app_secret=self.open_secrept,
                                 redirect_uri=self.open_redirect_uri)