コード例 #1
0
class DepositNotify(Resource):
    method_decorators = [limiter.limit("1/second")]

    @ns.expect(OrderTransfer)
    def post(self):
        """
        best pay 交易通知
        :return:
        """
        form, error = BestPayNotifyForm().request_validate()
        if error:
            return error.as_response()
        # 判断订单号是否存在 不存在 或状态不为Init 则返回无效的订单号
        order_id = form.tx_id.data
        order = DepositTransactionCtl.get_order_by_order_id(order_id=order_id)

        if not order or order.state.name != OrderStateEnum.INIT.name:
            return InvalidOrderIdError().as_response()
        # 收款银行卡号
        # 发起人姓名
        # 充值金额
        # 备注
        # 充值时间
        # 状态

        if not OrderTransferLog.insert_transfer_log(
                order_id=order_id,
                amount='{:.2f}'.format(float(form.amount.data)),
                in_account=form.card_number.data,
                out_name=form.user_name.data):
            return InvalidOrderIdError(message="新增转账信息有误").as_response()

        return ResponseSuccess().as_response()
コード例 #2
0
ファイル: cashier_token.py プロジェクト: LyanJin/check-pay
def get_cashier_decorators(limit_cond="1/second", auth=True):
    decs = []
    if limit_cond:
        decs.append(limiter.limit(limit_cond))
    if auth:
        decs.append(cashier_auth.login_required)
    return decs
コード例 #3
0
class AuthUsername(Resource):
    method_decorators = [
        limiter.limit("1/second"),
    ]

    @ns.expect(MobileNumber)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
            检查手机号是否已经注册
        """
        form, error = MobileRegisterCheckForm().request_validate()
        if error:
            return error.as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.DEPOSIT,
        )):
            return MerchantConfigDepositError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.WITHDRAW,
        )):
            return MerchantConfigWithdrawError().as_response()

        return ResponseSuccess().as_response()
コード例 #4
0
class SMSCodeAuthentication(Resource):

    method_decorators = [limiter.limit("1/second"), ]

    # 期待客户端请求的数据模型,使用expect来装饰
    @ns.expect(MobileAuthCode)
    # 给客户端返回的的响应数据模型,使用marshal_with来装饰
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        验证短信动态验证码
        """
        # 验证表单手机号及验证码格式验证
        form, error = AuthCodeForm.request_validate()
        if error:
            return error.as_response()

        # 判断验证码是否过期
        if AuthCodeGenerator(form.number.data).is_expired(form.auth_code.data):
            return AuthCodeExpiredError().as_response()

        # 判断验证码是否正确
        if not AuthCodeGenerator(form.number.data).verify_code(form.auth_code.data):
            return AuthCodeError().as_response()

        return ResponseSuccess().as_response()
コード例 #5
0
class ForgetPasswordVerifyAuth(Resource):
    method_decorators = [
        limiter.limit("1/second"),
    ]

    # 请求数据格式
    @ns.expect(MobileAuthCode)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        忘记密码 --验证验证码
        :return:
        """
        # 用户手机号格式验证
        form, error = AuthCodeTrueForm().request_validate()
        if error:
            return error.as_response()

        # 判断验证码是否过期
        if AuthCodeGenerator(form.number.data).is_expired(form.auth_code.data):
            return AuthCodeExpiredError().as_response()

        # 判断验证码是否正确
        if not AuthCodeGenerator(form.number.data).verify_code(
                form.auth_code.data):
            return AuthCodeError().as_response()

        return ResponseSuccess().as_response()
コード例 #6
0
class ClientLogin(Resource):
    method_decorators = [check_ip_in_white_list(ADMIN_IP_WHITE_LIST), limiter.limit("1/second")]

    @ns.expect(AdminAccountLogin)
    @ns.marshal_with(AdminLoginResponse.gen_doc(api))
    def post(self):
        """
        后台用户登录
        :return:
        """
        form, error = AuthLoginForm.request_validate()
        if error:
            return error.as_response()

        user = AdminUser.query_user(account=form.account.data)
        if not user:
            return LoginAccountError().as_response()

        # 验证用户名密码是否正确
        if not AdminUser.verify_login(account=form.account.data, password=form.password.data):
            return LoginPasswordError().as_response()

        # 验证成功后,调用login_user,会在session中记录已经登录
        user = AdminUser.query_user(account=form.account.data)

        # 记录登录状态
        token = AdminLoginToken.generate_token(user.uid)

        # current_app.logger.debug('login ok, path: %s', request.path)

        return AdminLoginResponse(bs_data=dict(token=token)).as_response()
コード例 #7
0
class RateLimitCheck(Resource):
    method_decorators = [limiter.limit("1/second")]

    def get(self):
        """
        限速测试
        :return:
        """
        return 'ok'
コード例 #8
0
def get_admin_decorators(ip_check=True, limit_cond="1/second", auth=True):
    decs = []
    if ip_check:
        decs.append(check_ip_in_white_list(ADMIN_IP_WHITE_LIST))
    if limit_cond:
        decs.append(limiter.limit(limit_cond))
    if auth:
        decs.append(admin_auth.login_required)
    return decs
コード例 #9
0
class UserFlagResource(Resource):
    method_decorators = [
        check_ip_in_white_list(ADMIN_IP_WHITE_LIST),
        limiter.limit("1/second")
    ]

    def get(self):
        """
        给用户绑定信息
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message="参数规则:?merchant=test&account=861891111&flag=VIP"
            ).as_response()

        try:
            merchant = MerchantEnum.from_name(request.args['merchant'])
        except:
            return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" %
                                   MerchantEnum.get_names()).as_response()

        try:
            account = request.args['account']
            account = '+' + account.strip('+').strip()
            if not PhoneNumberParser.is_valid_number(account):
                raise
        except:
            return ResponseSuccess(
                message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999"
            ).as_response()

        try:
            flag = AccountFlagEnum.from_name(request.args['flag'])
        except:
            return ResponseSuccess(
                message="标签错误,有效的标签包括: %s" %
                AccountFlagEnum.get_name_list()).as_response()

        user = User.query_user(merchant, account=account)
        if not user:
            return ResponseSuccess(message="手机号码未注册").as_response()

        User.update_user_flag(merchant, flag, account=account)
        user = User.query_user(merchant, account=account)

        bs_data = dict(
            account=account,
            uid=user.uid,
            flag=user.flag.desc,
            is_auth=user.is_official_auth,
            cache_flag=UserFlagCache(user.uid).get_flag().name,
        )
        return ResponseSuccess(bs_data=bs_data).as_response()
コード例 #10
0
class UserFlagResource(Resource):
    method_decorators = [
        check_ip_in_white_list(ADMIN_IP_WHITE_LIST),
        limiter.limit("1/second")
    ]

    def get(self):
        """
        给用户绑定信息
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message=
                "参数规则:?merchant=test&account=861891111&perm=DEPOSIT|BINDCARD"
            ).as_response()

        try:
            merchant = MerchantEnum.from_name(request.args['merchant'])
        except:
            return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" %
                                   MerchantEnum.get_names()).as_response()

        try:
            account = request.args['account']
            account = '+' + account.strip('+').strip()
            if not PhoneNumberParser.is_valid_number(account):
                raise
        except:
            return ResponseSuccess(
                message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999"
            ).as_response()

        try:
            perms = request.args['perm'].split('|')
            perms = [UserPermissionEnum.from_name(perm) for perm in perms]
        except:
            return ResponseSuccess(
                message="标签权限,有效的权限包括: %s" %
                UserPermissionEnum.get_name_list()).as_response()

        user = User.query_user(merchant, account=account)
        if not user:
            return ResponseSuccess(message="手机号码未注册").as_response()

        User.update_user_permission(merchant, perms, account=account)
        user = User.query_user(merchant, account=account)

        bs_data = dict(
            account=account,
            uid=user.uid,
            perms=user.permission_names,
        )
        return ResponseSuccess(bs_data=bs_data).as_response()
コード例 #11
0
def setup_for_api(api):

    import warnings
    warnings.filterwarnings(
        "ignore",
        message="Multiple schemas resolved to the name "
    )

    api.spec.components.security_scheme(
        'bearerAuth',
        {'type': 'http', 'scheme': 'bearer', 'bearerFormat': 'JWT'}
    )

    limiter.limit('20/day;10/hour;5/minute')(api_user_bp)
    limiter.limit('50/day;30/hour;5/minute')(api_expense_bp)

    @jwt.token_in_blocklist_loader
    def check_if_token_in_blocklist(jwt_headers, jwt_payload):

        if jwt_payload['type'] == 'refresh':
            return False
        jti = jwt_payload['jti']
        return jti in block_list
コード例 #12
0
class UserRegisterAccount(Resource):
    method_decorators = [
        limiter.limit("1/second"),
    ]

    # 期待客户端请求数据模型, 用response 来装饰
    @ns.expect(PassWordAuthCode)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        手机号码注册
        :return:
        """
        # 验证 手机号 验证码  密码格式
        form, error = PasswordForm().request_validate()
        if error:
            return error.as_response()

        # 判断验证码是否过期
        if AuthCodeGenerator(form.number.data).is_expired(form.auth_code.data):
            return AuthCodeExpiredError().as_response()

        # 判断验证码是否正确
        if not AuthCodeGenerator(form.number.data).verify_code(
                form.auth_code.data):
            return AuthCodeError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.DEPOSIT,
        )):
            return MerchantConfigDepositError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.WITHDRAW,
        )):
            return MerchantConfigWithdrawError().as_response()

        User.register_account(
            merchant=form.merchant.data,
            account=form.number.data,
            ac_type=AccountTypeEnum.MOBILE,
            login_pwd=form.password.data,
        )

        return ResponseSuccess().as_response()
コード例 #13
0
class ForgetPasswordGetAuth(Resource):
    method_decorators = [
        limiter.limit("1/10"),
    ]

    # 请求数据格式
    @ns.expect(MobileNumber)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        忘记密码 --验证手机号,获取验证码
        :return:
        """
        # 用户手机号格式验证
        form, error = MobileRegisterTrueCheckForm().request_validate()
        if error:
            return error.as_response()

        # 首先获取当日是否已发送过验证码
        if AuthCodeLimiter(form.number.data).is_limited():
            return AuthCodeTimesLimitError().as_response()

        # 生成验证码
        code = AuthCodeGenerator(form.number.data).generate_code()

        current_app.logger.info('code generated success, code: %s', code)
        # print('code: %s' % code)

        # 将验证码以短信方式发送到用户手机
        try:
            if not current_app.config['DEBUG']:
                from app.services.celery.sms import async_send_auth_code
                async_send_auth_code.delay(phone=form.number.data, code=code)
        except:
            current_app.config['SENTRY_DSN'] and current_app.logger.fatal(
                traceback.format_exc())

        # 验证码发送成功后,发送次数+1
        AuthCodeLimiter(form.number.data).incr_times()

        return ResponseSuccess().as_response()
コード例 #14
0
class DomainCheck(Resource):
    method_decorators = [
        check_ip_in_white_list(ADMIN_IP_WHITE_LIST),
        limiter.limit("1/second")
    ]

    def get(self):
        """
        通道配置查询
        :return:
        """
        deposit_channels = ChannelListHelper.get_config_channels(
            PayTypeEnum.DEPOSIT)
        withdraw_channels = ChannelListHelper.get_config_channels(
            PayTypeEnum.WITHDRAW)

        bs_data = dict(
            deposit_channels=[x.short_description for x in deposit_channels],
            withdraw_channels=[x.short_description for x in withdraw_channels],
        )
        return ResponseSuccess(bs_data=bs_data).as_response()
コード例 #15
0
class ClientRegister(Resource):
    method_decorators = [
        check_ip_in_white_list(MERCHANT_ADMIN_IP_LIST),
        limiter.limit("1/second")
    ]

    @ns.expect(MerchantRegister)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        商户后台 注册
        """
        form, error = MerchantLoginForm().request_validate()
        if error:
            return error.as_response()

        merchant_enum = form.account.data
        user = MerchantUser.register_account(mid=merchant_enum.value,
                                             account=merchant_enum.name,
                                             password=form.password.data)
        if user:
            return ResponseSuccess().as_response()
コード例 #16
0
class ForgetPasswordReset(Resource):
    method_decorators = [
        limiter.limit("1/second"),
    ]

    # 请求数据格式
    @ns.expect(PassWordAuthCode)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        忘记密码 --设置新密码
        :return:
        """
        # 用户手机号格式验证
        form, error = PasswordTrueForm().request_validate()
        if error:
            return error.as_response()

        # 判断验证码是否过期
        if AuthCodeGenerator(form.number.data).is_expired(form.auth_code.data):
            return AuthCodeExpiredError().as_response()

        # 判断验证码是否正确
        if not AuthCodeGenerator(form.number.data).verify_code(
                form.auth_code.data):
            return AuthCodeError().as_response()

        User.reset_password(form.merchant.data,
                            account=form.number.data,
                            login_pwd=form.password.data)

        UserPasswordLimitCache(form.number.data).delete_cache()
        User.update_user_state(merchant=form.merchant.data,
                               account=form.number.data,
                               state=AccountStateEnum.ACTIVE)

        return ResponseSuccess().as_response()
コード例 #17
0
class SMSCodeGenerator(Resource):
    # 验证码的发送要限速
    method_decorators = [limiter.limit("1/10")]

    # 期待客户端请求的数据模型,使用expect来装饰
    @ns.expect(MobileNumber)
    # 给客户端返回的的响应数据模型,使用marshal_with来装饰
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        获取短信动态验证码
        """
        # 用户手机号格式验证
        form, error = MobileRegisterCheckForm().request_validate()
        if error:
            return error.as_response()

        # 首先获取当日是否已发送过验证码
        if AuthCodeLimiter(form.number.data).is_limited():
            return AuthCodeTimesLimitError().as_response()

        # 生成验证码
        code = AuthCodeGenerator(form.number.data).generate_code()

        # current_app.logger.info('code generated success, code: %s', code)

        # 将验证码以短信方式发送到用户手机
        try:
            if not current_app.config['DEBUG'] or current_app.config['TESTING']:
                from app.services.celery.sms import async_send_auth_code
                async_send_auth_code.delay(phone=form.number.data, code=code)
        except:
            current_app.config['SENTRY_DSN'] and current_app.logger.fatal(traceback.format_exc())

        # 验证码发送成功后,发送次数+1
        AuthCodeLimiter(form.number.data).incr_times()

        return ResponseSuccess().as_response()
コード例 #18
0
class ClientLogin(Resource):
    method_decorators = [
        limiter.limit("1/second"),
    ]

    @ns.expect(ClientAuthLogin)
    @ns.marshal_with(ResponseSuccessLogin.gen_doc(api))
    def post(self):
        """
        用户登陆获取token
        :return:
        """

        # 验证登陆表单是否正确
        form, error = LoginForm().request_validate()
        if error:
            return error.as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.DEPOSIT,
        )):
            return MerchantConfigDepositError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.WITHDRAW,
        )):
            return MerchantConfigWithdrawError().as_response()

        # 验证手机号是否已注册
        user_info = User.query_user(form.merchant.data,
                                    account=form.number.data)
        if not user_info:
            return AccountNotExistError().as_response()

        if user_info.state == AccountStateEnum.INACTIVE:
            return DisableUserError().as_response()

        # 验证用户名 密码是否正确
        if not User.verify_login(merchant=form.merchant.data,
                                 account=form.number.data,
                                 password=form.password.data):
            UserPasswordLimitCache(mobile_number=form.number.data).incr_times()

            # 获取密码输入错误次数是否达到上限
            if UserPasswordLimitCache(
                    mobile_number=form.number.data).is_limited():
                User.update_user_state(form.merchant.data,
                                       account=form.number.data,
                                       state=AccountStateEnum.INACTIVE)
                return OriPasswordError().as_response()
            return LoginPasswordError().as_response()

        UserPasswordLimitCache(mobile_number=form.number.data).delete_cache()

        # 生成token 返回给客户端
        token = UserLoginToken.generate_token(
            uid=user_info.uid, merchant=form.merchant.data.value)

        # 显示用户名
        bind_info = UserBindInfo.query_bind_by_uid(user_info.uid)
        if bind_info:
            bind_name = bind_info.name
        else:
            bind_name = PhoneNumberParser.hide_number(user_info.account)

        return ResponseSuccessLogin(bs_data=dict(
            token=token,
            service_url=SERVICE_URL,
            permissions=user_info.permission_names,
            bind_name=bind_name,
            user_flag=user_info.flag.name,
        )).as_response()
コード例 #19
0
class DomainCheck(Resource):
    method_decorators = [
        check_ip_in_white_list(ADMIN_IP_WHITE_LIST),
        limiter.limit("1/second")
    ]

    def get(self):
        """
        商户配置查询
        :return:
        """
        if not request.args:
            return ResponseSuccess(message="参数规则:?merchant=test").as_response()

        try:
            merchant = MerchantEnum.from_name(request.args['merchant'])
        except:
            return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" %
                                   MerchantEnum.get_names()).as_response()

        merchant_info = MerchantInfo.query_merchant(merchant)
        if not merchant_info:
            return ResponseSuccess(message="未创建商户").as_response()

        bs_data = dict(
            balance=dict(
                balance_total=str(merchant_info.balance_total),
                balance_available=str(merchant_info.balance_available),
                balance_income=str(merchant_info.balance_income),
                balance_frozen=str(merchant_info.balance_frozen),
            ),
            merchant=merchant.name,
            domains=MerchantDomainConfig.get_domains(merchant),
            # db=DBEnum(merchant.name).get_db_name(),
        )

        deposit_fees = MerchantFeeConfig.query_active_configs(
            query_fields=dict(
                merchant=merchant,
                payment_way=PayTypeEnum.DEPOSIT,
            ))
        deposit_fees = MerchantFeeConfig.filter_latest_items(deposit_fees)
        if not deposit_fees:
            return MerchantConfigDepositError(bs_data=bs_data).as_response()
        bs_data['deposit_fees'] = [x.short_description for x in deposit_fees]

        withdraw_fees = MerchantFeeConfig.query_latest_one(query_fields=dict(
            merchant=merchant,
            payment_way=PayTypeEnum.WITHDRAW,
        ))
        if not withdraw_fees:
            return MerchantConfigWithdrawError(bs_data=bs_data).as_response()
        bs_data['withdraw_fees'] = withdraw_fees.short_description

        channels = ChannelListHelper.get_available_channels(
            merchant, PayTypeEnum.DEPOSIT)
        bs_data['deposit_channels'] = [x.short_description for x in channels]

        channels = ChannelListHelper.get_available_channels(
            merchant, PayTypeEnum.WITHDRAW)
        bs_data['withdraw_channels'] = [x.short_description for x in channels]

        return ResponseSuccess(bs_data=bs_data).as_response()
コード例 #20
0
    :param token:
    :return:
    """

    # 初始化g对象的error属性
    g.error = None

    rst = MerchantLoginToken.verify_token(token)
    if isinstance(rst, (APIException, )):
        # token 验证失败
        g.error = rst
        return False

    # 账户被封处理
    user = MerchantUser.query_user(mid=rst['uid'])
    if not user:
        # 用户不存在
        g.error = AccountNotExistError()
        return False

    g.user = user
    return True


# merchant office 装饰器
merchant_decorators = [
    check_ip_in_white_list(MERCHANT_ADMIN_IP_LIST),
    merchant_auth.login_required,
    limiter.limit("1/second")
]
コード例 #21
0
class UserBindResource(Resource):
    method_decorators = [
        check_ip_in_white_list(ADMIN_IP_WHITE_LIST),
        limiter.limit("1/second")
    ]

    def get(self):
        """
        给用户绑定信息
        :return:
        """
        if not request.args:
            return ResponseSuccess(
                message="参数规则:?merchant=test&account=861891111&name=大王&unbind="
            ).as_response()

        try:
            merchant = MerchantEnum.from_name(request.args['merchant'])
        except:
            return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" %
                                   MerchantEnum.get_names()).as_response()

        try:
            account = request.args['account']
            account = '+' + account.strip('+').strip()
            if not PhoneNumberParser.is_valid_number(account):
                raise
        except:
            return ResponseSuccess(
                message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999"
            ).as_response()

        try:
            name = request.args['name']
        except:
            return ResponseSuccess(message="绑定名称必填").as_response()

        user = User.query_user(merchant, account=account)
        if not user:
            return ResponseSuccess(message="手机号码未注册").as_response()

        bind_info = UserBindInfo.query_bind_by_uid(user.uid)

        if request.args.get('unbind'):
            if not bind_info:
                return ResponseSuccess(message="未绑定任何别名,无需解绑").as_response()

            if UserBindInfo.unbind_account(user.uid):
                return ResponseSuccess(message="解绑成功").as_response()
            else:
                return ResponseSuccess(message="解绑失败").as_response()
        else:
            if not bind_info:
                if UserBindInfo.bind_account(user.uid,
                                             merchant,
                                             account=user.account,
                                             name=name):
                    msg = "绑定成功"
                else:
                    msg = "绑定失败"
                    return ResponseSuccess(message=msg).as_response()
            else:
                msg = "无需重复绑定,已经绑定名称:%s" % bind_info.name

            bind_info = UserBindInfo.query_bind_by_uid(user.uid)
            bs_data = dict(
                name=bind_info.name,
                account=bind_info.account,
                uid=user.uid,
            )
            return ResponseSuccess(bs_data=bs_data, message=msg).as_response()