Beispiel #1
0
    def __init__(self, app_id, app_secret, token, encoding_aes_key=None):
        self.app_id = app_id if app_id else WX_OPEN_CONFIG['APP_ID']
        self.app_secret = app_secret if app_secret else WX_OPEN_CONFIG[
            'APP_SECRET']
        self.token = token if token else WX_OPEN_CONFIG['TOKEN']
        self.encoding_aes_key = encoding_aes_key if encoding_aes_key else WX_OPEN_CONFIG[
            'ENCODING_AES_KEY']

        # 加解密能力
        if self.encoding_aes_key:
            self.crypt = WXBizMsgCrypt(self.token, self.encoding_aes_key,
                                       self.app_id)

        # 会在 check_signature 方法中赋值
        self.signature = None
        self.timestamp = None
        self.nonce = None

        WX_OPEN_CONFIG['APP_ID'] = self.app_id
        WX_OPEN_CONFIG['APP_SECRET'] = self.app_secret
        WX_OPEN_CONFIG['TOKEN'] = self.token
        WX_OPEN_CONFIG['ENCODING_AES_KEY'] = self.encoding_aes_key

        # 启动计划任务
        task.task_client_start()
Beispiel #2
0
    def __init__(self, component_app_id, component_app_secret, component_token,
                 component_encoding_aes_key):
        self.component_app_id = component_app_id if component_app_id else WX_OPEN_THIRD_CONFIG[
            'COMPONENT_APP_ID']
        self.component_app_secret = component_app_secret if component_app_secret else WX_OPEN_THIRD_CONFIG[
            'COMPONENT_APP_SECRET']
        self.component_token = component_token if component_token else WX_OPEN_THIRD_CONFIG[
            'COMPONENT_TOKEN']
        self.component_encoding_aes_key = component_encoding_aes_key if component_encoding_aes_key else WX_OPEN_THIRD_CONFIG[
            'COMPONENT_ENCODING_AES_KEY']

        # 加解密能力
        self.crypt = WXBizMsgCrypt(self.component_token,
                                   self.component_encoding_aes_key,
                                   self.component_app_id)

        # API 路由能力
        self.router = WeChatThirdPlatformRouter(self.component_app_id,
                                                self.component_app_secret,
                                                self.component_access_token)

        # 会在 check_signature 方法中赋值
        self.signature = None
        self.timestamp = None
        self.nonce = None

        WX_OPEN_THIRD_CONFIG['COMPONENT_APP_ID'] = self.component_app_id
        WX_OPEN_THIRD_CONFIG[
            'COMPONENT_APP_SECRET'] = self.component_app_secret
        WX_OPEN_THIRD_CONFIG['COMPONENT_TOKEN'] = self.component_token
        WX_OPEN_THIRD_CONFIG[
            'COMPONENT_ENCODING_AES_KEY'] = self.component_encoding_aes_key

        # 启动计划任务
        task.task_third_start()
Beispiel #3
0
    def get_request(request):
        """开启回调模式,微信服务器会发送http-GET给企业的URL并验证.

        企业号将发送GET请求到填写的URL上,GET请求携带四个参数,企业在获取时需要做urldecode处理.
        企业通过参数msg_signature对请求进行校验,如果确认此次GET请求来自企业号,那么企业应该对echostr参数解密并原样返回echostr明文.
        (不能加引号,不能带bom头,不能带换行符),则接入验证生效,回调模式才能开启。
        """
        wxbmc = WXBizMsgCrypt(TOKEN, EncodingAESKey, CORPID)
        msg_signature = request.GET.get('msg_signature')
        timestamp = request.GET.get('timestamp')
        nonce = request.GET.get('nonce')
        # echostr首次校验时必带
        echostr = request.GET.get('echostr')
        ret, reply_echostr = wxbmc.VerifyURL(msg_signature, timestamp, nonce,
                                             echostr)
        if ret != 0:
            return ret
        return reply_echostr
Beispiel #4
0
def wx_message():
    req = request.args
    signature = req.get('signature', '')
    timestamp = req.get('timestamp', '')
    nonce = req.get('nonce', '')
    if not check_signature(signature, timestamp, nonce):
        logging.warning("check signature fail")
        return ''

    logging.debug("req args:%s", req)
    logging.debug("data:%s", request.data)
    msg_signature = req.get('msg_signature')
    if not msg_signature:
        logging.warning("msg signature is None")
        return ''

    try:
        data = Parse.parse(request.data)
        encrypted_data = data.get("Encrypt")
        wx_crypt = WXBizMsgCrypt(TOKEN, ENCODING_AES_KEY, APPID)
        r, xml = wx_crypt.DecryptTicket(request.data, msg_signature, timestamp,
                                        nonce)
        logging.debug("ret:%s xml:%s", r, xml)
        if r == 0 and xml:
            data = Parse.parse(xml)
    except Exception, e:
        logging.error("exception:%s", e)
        wx_crypt = WXBizMsgCrypt(TOKEN, ENCODING_AES_KEY, APPID)
        r, xml = wx_crypt.DecryptTicket(request.data, msg_signature, timestamp,
                                        nonce)
        logging.debug("ret:%s xml:%s", r, xml)
        data = Parse.parse(xml)
Beispiel #5
0
 def render(self):
     xml_response = xmltodict.unparse(self.dict())
     if WX_OPEN_CONFIG['ENCODING_AES_KEY']:
         encrypt = WXBizMsgCrypt(WX_OPEN_CONFIG['token'], WX_OPEN_CONFIG['ENCODING_AES_KEY'], WX_OPEN_CONFIG['APP_ID'])
         ret, xml_response = encrypt.EncryptMsg(xml_response, self._get_nonce())
     return xml_response
Beispiel #6
0
import urllib2
from werkzeug.contrib.cache import SimpleCache

# from wechatpy.enterprise import create_reply, parse_message
# from wechatpy.enterprise.crypto import WeChatCrypto

app = Flask(__name__)

# 假设企业在企业微信后台上设置的参数如下
sAgent_id = "1000002"
sCorpID = "ww532b5887083931ac"
sToken = "hJqcu3uJ9Tn2gXPmxx2w9kkCkCE2EPYo"
sEncodingAESKey = "6qkdMrq68nTKduznJYO1A37W2oEgpkMUvkttRToqhUt"
sSecret = "S0zjZTT7lnk48cC5y6PWVXpZJVKtGly2c1zJt5Fm1Rs"

wxcpt = WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID)
cache = SimpleCache()


def getToken():
    params_dic = {'corpid': sCorpID, 'corpsecret': sSecret}
    url_params = urllib.urlencode(params_dic)
    url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" + url_params
    try:
        req_obj = urllib2.Request(url)
    except KeyError:
        raise KeyError
    result = urllib2.urlopen(req_obj)
    access_token_dic = json.load(result)
    return access_token_dic['access_token'], access_token_dic['expires_in']
Beispiel #7
0
def receive(wx_appid):
    db = g._db
    rds = g.im_rds
    req = request.args
    signature = req.get('signature', '')
    timestamp = req.get('timestamp', '')
    nonce = req.get('nonce', '')
    if not check_signature(signature, timestamp, nonce):
        logging.warning("check signature fail")
        return ''

    msg_signature = req.get('msg_signature')
    if not msg_signature:
        logging.warning("msg signature is None")
        return ''

    wx_crypt = WXBizMsgCrypt(TOKEN, ENCODING_AES_KEY, APPID)
    r, xml = wx_crypt.DecryptMsg(request.data, msg_signature, timestamp, nonce)

    logging.debug("receive wx message:%s %s %s", wx_appid, r, xml)

    data = Parse.parse(xml)
    msg_type = data.get('MsgType')

    # 接收到事件
    if msg_type == 'event':
        logging.debug("event:%s", data.get('Event'))
        event = data.get('Event')
        session = data.get('SessionFrom')
        openid = data.get('FromUserName')
        gh_id = data.get('ToUserName')
        if event == 'user_enter_tempsession' and session:
            #设置来自小程序的微信用户名
            u = get_user(rds, db, gh_id, openid)
            if u:
                logging.debug("set user name:%s %s %s", gh_id, openid, session)
                WXUser.set_user_name(rds, u.appid, u.uid, session)
        return ''
    # 接收到其他消息
    else:
        openid = data.get('FromUserName')
        gh_id = data.get('ToUserName')

        # 消息格式检查
        if msg_type not in ('text', 'image', 'voice', 'location'):
            msg = Reply.text(openid, gh_id, '该消息格式不支持, 目前只支持文本,图片,语音,位置')
            _, m = wx_crypt.EncryptMsg(msg, nonce, timestamp)
            return m

        logging.debug("msg:%s %s %s", openid, gh_id, msg_type)

        u = get_user(rds, db, gh_id, openid)
        logging.debug("appid:%s uid:%s store id:%s seller id:%s", u.appid,
                      u.uid, u.store_id, u.seller_id)
        if msg_type == 'text':
            content = data.get('Content')
            logging.debug("text content:%s", content)
            obj = {"text": content}
        elif msg_type == 'location':
            x = data.get("Location_X")
            y = data.get("Location_Y")
            obj = {"location": {"latitude": x, "longitude": y}}
        elif msg_type == 'image':
            access_token = get_access_token(rds, db, u.wx_appid)
            if not access_token:
                logging.error("can't get access token")
                return ''

            mp = WXMPAPI(access_token)
            media = mp.get_media(data.get("MediaId"))
            try:
                width, height = get_image_size(media)
            except UnknownImageFormat, e:
                width = 0
                height = 0

            ext = ".jpg"
            name = md5.new(media).hexdigest()
            path = "/images/" + name + ext
            r = FS.upload(path, media)
            if not r:
                logging.error("fs upload image error")
                return ''

            url = config.IM_URL + "/images/" + name + ext
            image2 = {"url": url, "width": width, "height": height}
            obj = {"image": url, "image2": image2}
            logging.debug("image url:%s width:%s height:%s", url, width,
                          height)
        elif msg_type == 'voice':
            access_token = get_access_token(rds, db, u.wx_appid)
            if not access_token:
                logging.error("can't get access token")
                return ''

            mp = WXMPAPI(access_token)
            media = mp.get_media(data.get("MediaId"))

            md5_value = md5.new(media).hexdigest()
            path = "/audios/" + md5_value
            r = FS.upload(path, media)
            if not r:
                logging.error("fs upload audio error")
                return ''

            duration = amr_duration(media)
            url = config.IM_URL + "/audios/" + md5_value
            obj = {"audio": {"url": url, "duration": duration}}
Beispiel #8
0
    def post_request(request):
        """使用回调模式,用户通过微信企业号给企业的URL通过http-POST发送消息,企业对此进行回复.

        企业号在回调企业URL时,会对消息体本身做AES加密,以XML格式POST到企业应用的URL上;
        企业在被动响应时,也需要对数据加密,以XML格式返回给微信。
        """
        wxbmc = WXBizMsgCrypt(TOKEN, EncodingAESKey, CORPID)
        postdata = request.body
        msg_signature = request.GET.get('msg_signature')
        timestamp = request.GET.get('timestamp')
        nonce = request.GET.get('nonce')
        ret, xml_content = wxbmc.DecryptMsg(postdata, msg_signature, timestamp,
                                            nonce)
        if ret != 0:
            return ret
        request_map = MessageUtil.parse_xml(xml_content)
        receive_basic_object = BasicReceive(request_map)
        MsgType = receive_basic_object.MsgType
        ToUserName = receive_basic_object.ToUserName
        FromUserName = receive_basic_object.FromUserName

        # Response to different request message type.
        if MsgType == REC_MESSAGE_TYPE_TEXT:
            receive_text_object = TextMsg(request_map)
            receive_content = receive_text_object.Content
            response_content = handle_tuling_robot(receive_content,
                                                   FromUserName)
            if not response_content:
                response_content = u"Useless text!"
            response_text_object = Text(FromUserName, ToUserName,
                                        response_content)
            ret, encryptmsg = wxbmc.EncryptMsg(response_text_object.response(),
                                               nonce, timestamp)
            if ret != 0:
                return BasicResponse().response()
            return encryptmsg
        elif MsgType == REC_MESSAGE_TYPE_IMAGE:
            receive_image_object = ImageMsg(request_map)
            PicUrl = receive_image_object.PicUrl
            response_content = handle_how_old(PicUrl)
            if not response_content:
                response_content = u"Useless image!"
            response_image_object = Text(FromUserName, ToUserName,
                                         response_content)
            ret, encryptmsg = wxbmc.EncryptMsg(
                response_image_object.response(), nonce, timestamp)
            if ret != 0:
                return BasicResponse().response()
            return encryptmsg
        elif MsgType == REC_MESSAGE_TYPE_VOICE:
            return BasicResponse().response()
        elif MsgType == REC_MESSAGE_TYPE_VIDEO:
            return BasicResponse().response()
        elif MsgType == REC_MESSAGE_TYPE_SHORTVIDEO:
            return BasicResponse().response()
        elif MsgType == REC_MESSAGE_TYPE_LOCATION:
            return BasicResponse().response()
        elif MsgType == REC_MESSAGE_TYPE_LINK:
            return BasicResponse().response()
        elif MsgType == REC_MESSAGE_TYPE_EVENT:
            Event = request_map.get(u'Event')
            if Event == EVENT_SUBSCRIBE:
                return BasicResponse().response()
            elif Event == EVENT_UNSUBSCRIBE:
                return BasicResponse().response()
            else:
                return BasicResponse.response()
        else:
            return BasicResponse().response()
Beispiel #9
0
class WeChatClient:
    """
    微信公众号
    """
    def __init__(self, app_id, app_secret, token, encoding_aes_key=None):
        self.app_id = app_id if app_id else WX_OPEN_CONFIG['APP_ID']
        self.app_secret = app_secret if app_secret else WX_OPEN_CONFIG[
            'APP_SECRET']
        self.token = token if token else WX_OPEN_CONFIG['TOKEN']
        self.encoding_aes_key = encoding_aes_key if encoding_aes_key else WX_OPEN_CONFIG[
            'ENCODING_AES_KEY']

        # 加解密能力
        if self.encoding_aes_key:
            self.crypt = WXBizMsgCrypt(self.token, self.encoding_aes_key,
                                       self.app_id)

        # 会在 check_signature 方法中赋值
        self.signature = None
        self.timestamp = None
        self.nonce = None

        WX_OPEN_CONFIG['APP_ID'] = self.app_id
        WX_OPEN_CONFIG['APP_SECRET'] = self.app_secret
        WX_OPEN_CONFIG['TOKEN'] = self.token
        WX_OPEN_CONFIG['ENCODING_AES_KEY'] = self.encoding_aes_key

        # 启动计划任务
        task.task_client_start()

    def process(self, raw_data):
        """
        消息处理
        :param raw_data: 原生微信返回的数据格式
        :return:
        """
        # 解密消息
        if self.encoding_aes_key:
            ret, raw_data = self.crypt.DecryptMsg(raw_data, self.signature,
                                                  self.timestamp, self.nonce)

        message = parse_message(raw_data)
        if message.msg_type == 'event':
            if funcs.get(message.event.lower()):
                return funcs.get(message.event.lower())(message)
        else:
            if funcs.get(message.msg_type.lower()):
                return funcs.get(message.msg_type.lower())(message)
        print(UnimplementedMsgMethodException(method=message.msg_type))
        return SuccessReply().render()

    def check_signature(self, signature, timestamp, nonce):
        """
        签名校验
        :param signature: 微信加密签名
        :param timestamp: 时间戳
        :param nonce: 随机数
        :return:
        """
        # 校验参数
        if not all([signature, timestamp, nonce]):
            raise MissingParametersException()

        # 计算签名
        li = [self.token, timestamp, nonce]
        li.sort()  # 字典排序
        tmp_str = ''.join(li)  # 拼接字符串
        _signature = hashlib.sha1(tmp_str.encode('utf-8')).hexdigest()

        # 与微信服务器进行签名对比
        if _signature != signature:
            raise InvalidSignatureException()

        self.signature = signature
        self.timestamp = timestamp
        self.nonce = nonce

        return True

    @property
    def access_token(self):
        return memory_cache.get(constants.ACCESS_TOKEN)
Beispiel #10
0
class WeChatThirdClient:
    """
    微信第三方平台
    """
    def __init__(self, component_app_id, component_app_secret, component_token,
                 component_encoding_aes_key):
        self.component_app_id = component_app_id if component_app_id else WX_OPEN_THIRD_CONFIG[
            'COMPONENT_APP_ID']
        self.component_app_secret = component_app_secret if component_app_secret else WX_OPEN_THIRD_CONFIG[
            'COMPONENT_APP_SECRET']
        self.component_token = component_token if component_token else WX_OPEN_THIRD_CONFIG[
            'COMPONENT_TOKEN']
        self.component_encoding_aes_key = component_encoding_aes_key if component_encoding_aes_key else WX_OPEN_THIRD_CONFIG[
            'COMPONENT_ENCODING_AES_KEY']

        # 加解密能力
        self.crypt = WXBizMsgCrypt(self.component_token,
                                   self.component_encoding_aes_key,
                                   self.component_app_id)

        # API 路由能力
        self.router = WeChatThirdPlatformRouter(self.component_app_id,
                                                self.component_app_secret,
                                                self.component_access_token)

        # 会在 check_signature 方法中赋值
        self.signature = None
        self.timestamp = None
        self.nonce = None

        WX_OPEN_THIRD_CONFIG['COMPONENT_APP_ID'] = self.component_app_id
        WX_OPEN_THIRD_CONFIG[
            'COMPONENT_APP_SECRET'] = self.component_app_secret
        WX_OPEN_THIRD_CONFIG['COMPONENT_TOKEN'] = self.component_token
        WX_OPEN_THIRD_CONFIG[
            'COMPONENT_ENCODING_AES_KEY'] = self.component_encoding_aes_key

        # 启动计划任务
        task.task_third_start()

    def process(self, raw_data):
        """
        消息处理
        :param raw_data: 原生微信返回的数据格式
        :return:
        """
        # 解密消息
        ret, raw_data = self.crypt.DecryptMsg(raw_data, self.signature,
                                              self.timestamp, self.nonce)

        # 存储 ComponentVerifyTicket
        if raw_data['InfoType'] == 'component_verify_ticket':
            memory_cache.set(constants.COMPONENT_VERIFY_TICKET,
                             raw_data['ComponentVerifyTicket'])
            return SuccessReply().render()

        message = parse_message(raw_data)
        to_user_name = message.to_user_name
        content = message.content

        if message.msg_type == 'event':
            # 全网发布检测(事件级别)
            if to_user_name == constants.TEST_WHOLE_NETWORK_PUBLISH_USERNAME:
                event_type = message.event
                content = event_type + 'from_callback'
                return TextReply(message, content).render()

            # 事件消息注册
            if funcs.get(message.event.lower()):
                return funcs.get(message.event.lower())(message)
        else:
            # 全网发布检测(消息级别)
            if to_user_name == constants.TEST_WHOLE_NETWORK_PUBLISH_USERNAME:
                if message.msg_type.lower() == 'text':

                    # 测试公众号处理用户消息
                    if content == 'TESTCOMPONENT_MSG_TYPE_TEXT':
                        content += '_callback'
                        return TextReply(message, content).render()

                    # 测试公众号使用客服消息接口处理用户消息
                    elif content.startswith('QUERY_AUTH_CODE:'):
                        query_auth_code = content.split(":")[1]
                        result = self.router.api_query_auth(query_auth_code)
                        authorizer_access_token = result['authorization_info'][
                            'authorizer_access_token']
                        from_user_name = message.from_user_name
                        content = query_auth_code + '_from_api'
                        from client.request import CustomerRequest
                        return CustomerRequest(
                            authorizer_access_token).send_text(
                                from_user_name, content)

            # 常规消息注册
            if funcs.get(message.msg_type.lower()):
                return funcs.get(message.msg_type.lower())(message)

        print(UnimplementedMsgMethodException(method=message.msg_type))
        return SuccessReply().render()

    def check_signature(self, signature, timestamp, nonce):
        """
        签名校验
        :param signature: 微信加密签名
        :param timestamp: 时间戳
        :param nonce: 随机数
        :return:
        """
        # 校验参数
        if not all([signature, timestamp, nonce]):
            raise MissingParametersException()

        # 计算签名
        li = [self.component_token, timestamp, nonce]
        li.sort()  # 字典排序
        tmp_str = ''.join(li)  # 拼接字符串
        _signature = hashlib.sha1(tmp_str.encode('utf-8')).hexdigest()

        # 与微信服务器进行签名对比
        if _signature != signature:
            raise InvalidSignatureException()

        self.signature = signature
        self.timestamp = timestamp
        self.nonce = nonce

        return True

    @property
    def component_access_token(self):
        return memory_cache.get(constants.COMPONENT_ACCESS_TOKEN)