Example #1
0
    def get_subscribe_authorize_url(self,
                                    scene,
                                    template_id,
                                    redirect_url,
                                    reserved=None):
        """
        构造请求用户授权的url
        详情请参阅:
        https://mp.weixin.qq.com/wiki?id=mp1500374289_66bvB

        :param scene: 订阅场景值,开发者可以填0-10000的整形值,用来标识订阅场景值
        :type scene: int
        :param template_id: 订阅消息模板ID,登录公众平台后台,在接口权限列表处可查看订阅模板ID
        :param redirect_url: 授权后重定向的回调地址
        :param reserved: 用于保持请求和回调的状态,授权请后原样带回给第三方。该参数可用于防止csrf攻击。若不指定则随机生成。
        """
        if reserved is None:
            reserved = random_string()
        base_url = 'https://mp.weixin.qq.com/mp/subscribemsg'
        params = [
            ('action', 'get_confirm'),
            ('appid', self.appid),
            ('scene', scene),
            ('template_id', template_id),
            ('redirect_url', redirect_url),
            ('reserved', reserved),
        ]
        encoded_params = six.moves.urllib.parse.urlencode(params)
        url = '{base}?{params}#wechat_redirect'.format(base=base_url,
                                                       params=encoded_params)
        return url
Example #2
0
    async def get_jsapi_params(self,
                               prepay_id,
                               timestamp=None,
                               nonce_str=None,
                               jssdk=False):
        """
        获取 JSAPI 参数

        :param prepay_id: 统一下单接口返回的 prepay_id 参数值
        :param timestamp: 可选,时间戳,默认为当前时间戳
        :param nonce_str: 可选,随机字符串,默认自动生成
        :param jssdk: 前端调用方式,默认使用 WeixinJSBridge
                      使用 jssdk 调起支付的话,timestamp 的 s 为小写
                      使用 WeixinJSBridge 调起支付的话,timeStamp 的 S 为大写
        :return: 参数
        """
        data = {
            'appId': self.sub_appid or self.appid,
            'timeStamp': timestamp or to_text(int(time.time())),
            'nonceStr': nonce_str or random_string(32),
            'signType': 'MD5',
            'package': 'prepay_id={0}'.format(prepay_id),
        }
        sign = calculate_signature(
            data, self._client.api_key if not self._client.sandbox else await
            self._client.sandbox_api_key())
        logger.debug('JSAPI payment parameters: data = %s, sign = %s', data,
                     sign)
        data['paySign'] = sign
        if jssdk:
            data['timestamp'] = data.pop('timeStamp')
        return data
Example #3
0
    async def _request(self, method, url_or_endpoint, **kwargs):
        if not url_or_endpoint.startswith(('http://', 'https://')):
            api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL)
            if self.sandbox:
                api_base_url = '{url}sandboxnew/'.format(url=api_base_url)
            url = '{base}{endpoint}'.format(
                base=api_base_url,
                endpoint=url_or_endpoint
            )
        else:
            url = url_or_endpoint

        params = kwargs.pop('params', {})
        params = urlencode(dict((k, to_binary(v)) for k, v in params.items()))
        url = '{0}?{1}'.format(url, params)

        data = kwargs.pop('data', {})

        if isinstance(data, dict):
            if 'mchid' not in data:
                data.setdefault('mch_id', self.mch_id)
            data.setdefault('sub_mch_id', self.sub_mch_id)
            data.setdefault('nonce_str', random_string(32))
            data = optionaldict(data)

            if data.get('sign_type', 'MD5') == 'HMAC-SHA256':
                sign = calculate_signature_hmac(data, await self.sandbox_api_key() if self.sandbox else self.api_key)
            else:
                sign = calculate_signature(data, await self.sandbox_api_key() if self.sandbox else self.api_key)
            body = dict_to_xml(data, sign)
            body = body.encode('utf-8')
            kwargs['body'] = body

        # 商户证书
        if self.mch_cert and self.mch_key:
            ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            ssl_ctx.load_cert_chain(self.mch_cert, self.mch_key)
            kwargs['ssl_options'] = ssl_ctx

        kwargs['request_timeout'] = kwargs.pop('timeout') if 'timeout' in kwargs else self.timeout
        logger.debug('Request to WeChat API: %s %s\n%s', method, url, kwargs)

        req = HTTPRequest(
            url,
            method=method,
            **kwargs
        )

        res = await self._http.fetch(req)
        if res.error is not None:
            raise WeChatPayException(
                return_code=None,
                client=self,
                request=req,
                response=res
            )

        return self._handle_result(res)
Example #4
0
 async def _fetch_sandbox_api_key(self):
     nonce_str = random_string(32)
     sign = calculate_signature({'mch_id': self.mch_id, 'nonce_str': nonce_str}, self.api_key)
     payload = dict_to_xml({
         'mch_id': self.mch_id,
         'nonce_str': nonce_str,
     }, sign=sign)
     headers = {'Content-Type': 'text/xml'}
     api_url = '{base}sandboxnew/pay/getsignkey'.format(base=self.API_BASE_URL)
     request = HTTPRequest(api_url, method='POST', body=payload, headers=headers)
     response = await self._http.fetch(request)
     return xmltodict.parse(response.body.decode('utf-8'))['xml'].get('sandbox_signkey')
Example #5
0
    def get_appapi_params(self, prepay_id, timestamp=None, nonce_str=None):
        """
        获取 APP 支付参数

        :param prepay_id: 统一下单接口返回的 prepay_id 参数值
        :param timestamp: 可选,时间戳,默认为当前时间戳
        :param nonce_str: 可选,随机字符串,默认自动生成
        :return: 签名
        """
        data = {
            'appid': self.appid,
            'partnerid': self.mch_id,
            'prepayid': prepay_id,
            'package': 'Sign=WXPay',
            'timestamp': timestamp or to_text(int(time.time())),
            'noncestr': nonce_str or random_string(32)
        }
        sign = calculate_signature(data, self._client.api_key)
        data['sign'] = sign
        return data
Example #6
0
 def get_jsapi_card_params(self, card_ticket, card_type, **kwargs):
     """
     参数意义见微信文档地址:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62
     :param card_ticket: 用于卡券的微信 api_ticket
     :param card_type:
     :param kwargs: 非必须参数:noncestr, timestamp, code, openid, fixed_begintimestamp, outer_str
     :return: 包含调用jssdk所有所需参数的 dict
     """
     card_signature_dict = {
         'card_type': card_type,
         'noncestr': kwargs.get('noncestr', random_string()),
         'api_ticket': card_ticket,
         'appid': self.appid,
         'timestamp': kwargs.get('timestamp', str(int(time.time()))),
     }
     list_before_sign = sorted(
         [str(x) for x in card_signature_dict.values()])
     str_to_sign = "".join(list_before_sign).encode()
     card_signature_dict['sign'] = hashlib.sha1(str_to_sign).hexdigest()
     return card_signature_dict
Example #7
0
    async def get_jsapi_signature(self,
                                  prepay_id,
                                  timestamp=None,
                                  nonce_str=None):
        """
        获取 JSAPI 签名

        :param prepay_id: 统一下单接口返回的 prepay_id 参数值
        :param timestamp: 可选,时间戳,默认为当前时间戳
        :param nonce_str: 可选,随机字符串,默认自动生成
        :return: 签名
        """
        data = {
            'appId': self.sub_appid or self.appid,
            'timeStamp': timestamp or to_text(int(time.time())),
            'nonceStr': nonce_str or random_string(32),
            'signType': 'MD5',
            'package': 'prepay_id={0}'.format(prepay_id),
        }
        return calculate_signature(
            data, self._client.api_key if not self._client.sandbox else await
            self._client.sandbox_api_key())
Example #8
0
 def get_random_string(self):
     return random_string(16)