前言

游戏出海需要面对不同地区的支付习惯和监管要求。构建一套安全、合规、灵活的支付系统是游戏成功出海的关键。本文将深入探讨全球化支付系统的设计与实现。

多渠道支付系统

1. 支付网关集成

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// 支付提供商接口
interface PaymentProvider {
    name: string;
    supportedRegions: string[];
    supportedCurrencies: string[];

    createCharge(request: ChargeRequest): Promise<ChargeResponse>;
    refundCharge(chargeId: string, amount?: number): Promise<RefundResponse>;
    retrieveCharge(chargeId: string): Promise<Charge>;
    webhookVerify(signature: string, payload: string): boolean;
}

// 支付管理器
class PaymentManager {
    private providers = new Map<string, PaymentProvider>();
    private defaultProvider: string;

    // 注册支付提供商
    registerProvider(provider: PaymentProvider): void {
        this.providers.set(provider.name, provider);
    }

    // 创建支付
    async createCharge(request: CreateChargeRequest): Promise<PaymentResult> {
        const { userId, amount, currency, region, metadata } = request;

        // 1. 风险检查
        const riskCheck = await this.performRiskCheck(userId, amount, region);
        if (riskCheck.risk > riskCheck.threshold) {
            throw new PaymentError('HIGH_RISK', 'Transaction flagged as high risk');
        }

        // 2. 选择支付提供商
        const provider = this.selectProvider(region, currency);
        if (!provider) {
            throw new PaymentError('NO_PROVIDER', `No payment provider for ${region}/${currency}`);
        }

        // 3. 转换金额
        const convertedAmount = await this.convertCurrency(amount, currency, region);

        // 4. 创建支付
        const chargeRequest: ChargeRequest = {
            amount: convertedAmount,
            currency,
            description: metadata.description,
            metadata: {
                userId,
                gameId: metadata.gameId,
                serverId: metadata.serverId
            }
        };

        const charge = await provider.createCharge(chargeRequest);

        // 5. 记录交易
        await this.recordTransaction({
            chargeId: charge.id,
            provider: provider.name,
            userId,
            amount: convertedAmount,
            currency,
            status: 'pending',
            metadata
        });

        return {
            chargeId: charge.id,
            amount: convertedAmount,
            currency,
            status: charge.status,
            redirectUrl: charge.redirectUrl,
            provider: provider.name
        };
    }

    // 选择支付提供商
    private selectProvider(region: string, currency: string): PaymentProvider | null {
        // 按优先级排序的提供商列表
        const priority = [
            'stripe',
            'paypal',
            'alipay',
            'wechat_pay',
            'local_bank'
        ];

        for (const name of priority) {
            const provider = this.providers.get(name);
            if (provider &&
                provider.supportedRegions.includes(region) &&
                provider.supportedCurrencies.includes(currency)) {
                return provider;
            }
        }

        return null;
    }

    // 处理Webhook
    async handleWebhook(
        providerName: string,
        signature: string,
        payload: string
    ): Promise<void> {
        const provider = this.providers.get(providerName);
        if (!provider) {
            throw new Error(`Unknown provider: ${providerName}`);
        }

        // 验证签名
        if (!provider.webhookVerify(signature, payload)) {
            throw new PaymentError('INVALID_SIGNATURE', 'Webhook signature verification failed');
        }

        // 解析事件
        const event = JSON.parse(payload);

        // 处理不同类型的事件
        switch (event.type) {
            case 'charge.succeeded':
                await this.handleChargeSucceeded(event.data);
                break;

            case 'charge.failed':
                await this.handleChargeFailed(event.data);
                break;

            case 'charge.refunded':
                await this.handleChargeRefunded(event.data);
                break;

            default:
                console.log('Unhandled webhook event type:', event.type);
        }
    }

    // 处理支付成功
    private async handleChargeSucceeded(data: any): Promise<void> {
        const { chargeId } = data;

        // 更新交易状态
        await this.updateTransactionStatus(chargeId, 'succeeded');

        // 获取交易记录
        const transaction = await this.getTransaction(chargeId);

        // 发放游戏内货币
        await this.grantInGameCurrency(
            transaction.metadata.userId,
            transaction.metadata.gameId,
            transaction.amount
        );

        // 发送通知
        await this.sendPaymentSuccessNotification(transaction);
    }
}

2. 本地化支付方式

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// 本地支付提供商配置
class LocalPaymentProviders {
    private providers = new Map<string, LocalPaymentProvider>();

    constructor() {
        this.registerProviders();
    }

    // 注册本地支付提供商
    private registerProviders(): void {
        // 中国:支付宝
        this.providers.set('alipay', new AlipayProvider());

        // 中国:微信支付
        this.providers.set('wechat_pay', new WeChatPayProvider());

        // 东南亚:Dana/OVO/Gopay
        this.providers.set('dana', new DanaProvider());
        this.providers.set('ovo', new OVOProvider());
        this.providers.set('gopay', new GopayProvider());

        // 韩国:Kakao Pay
        this.providers.set('kakao_pay', new KakaoPayProvider());

        // 日本:PayPay/Konbini
        this.providers.set('paypay', new PayPayProvider());
        this.providers.set('konbini', new KonbiniProvider());

        // 巴西:Pix
        this.providers.set('pix', new PixProvider());
    }

    // 获取指定地区的支付方式
    getPaymentMethods(region: string): PaymentMethod[] {
        const methods: PaymentMethod[] = [];

        // 通用支付方式
        methods.push(
            { id: 'card', name: 'Credit Card', icon: 'card', enabled: true },
            { id: 'paypal', name: 'PayPal', icon: 'paypal', enabled: region !== 'CN' }
        );

        // 本地支付方式
        switch (region) {
            case 'CN':
                methods.push(
                    { id: 'alipay', name: '支付宝', icon: 'alipay', enabled: true },
                    { id: 'wechat_pay', name: '微信支付', icon: 'wechat', enabled: true }
                );
                break;

            case 'ID':
                methods.push(
                    { id: 'dana', name: 'Dana', icon: 'dana', enabled: true },
                    { id: 'ovo', name: 'OVO', icon: 'ovo', enabled: true },
                    { id: 'gopay', name: 'GoPay', icon: 'gopay', enabled: true }
                );
                break;

            case 'KR':
                methods.push(
                    { id: 'kakao_pay', name: 'Kakao Pay', icon: 'kakao', enabled: true }
                );
                break;

            case 'JP':
                methods.push(
                    { id: 'paypay', name: 'PayPay', icon: 'paypay', enabled: true },
                    { id: 'konbini', name: 'Konbini', icon: 'konbini', enabled: true }
                );
                break;

            case 'BR':
                methods.push(
                    { id: 'pix', name: 'Pix', icon: 'pix', enabled: true }
                );
                break;
        }

        return methods;
    }
}

// 支付宝集成
class AlipayProvider implements LocalPaymentProvider {
    name = 'alipay';
    supportedRegions = ['CN'];

    async createPayment(order: PaymentOrder): Promise<PaymentResult> {
        // 调用支付宝API
        const params = {
            out_trade_no: order.id,
            total_amount: order.amount.toString(),
            subject: order.description,
            notify_url: this.getNotifyUrl()
        };

        const response = await this.callAPI('alipay.trade.create', params);

        return {
            paymentId: response.trade_no,
            paymentUrl: response.payment_url,
            qrCode: response.qr_code
        };
    }

    async queryPayment(paymentId: string): Promise<PaymentStatus> {
        const response = await this.callAPI('alipay.trade.query', {
            out_trade_no: paymentId
        });

        return {
            status: response.trade_status,
            amount: parseFloat(response.total_amount)
        };
    }
}

风控系统

1. 实时风控

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// 风控引擎
class RiskControlEngine {
    private rules = new Map<string, RiskRule>();
    private models = new Map<string, RiskModel>();
    private blacklists = new Map<string, Set<string>>();

    // 评估风险
    async evaluateRisk(transaction: PaymentTransaction): Promise<RiskAssessment> {
        const factors: RiskFactor[] = [];

        // 1. 设备指纹检查
        const deviceRisk = await this.checkDeviceRisk(transaction.deviceId);
        factors.push(deviceRisk);

        // 2. 用户行为分析
        const behaviorRisk = await this.analyzeUserBehavior(transaction.userId);
        factors.push(behaviorRisk);

        // 3. 交易模式检查
        const patternRisk = await this.checkTransactionPattern(transaction);
        factors.push(patternRisk);

        // 4. 地理位置
        const locationRisk = await this.checkLocation(transaction);
        factors.push(locationRisk);

        // 5. 黑名单检查
        const blacklistRisk = await this.checkBlacklists(transaction);
        factors.push(blacklistRisk);

        // 6. 机器学习模型预测
        const modelRisk = await this.predictRisk(transaction, factors);
        factors.push(modelRisk);

        // 计算综合风险分数
        const score = this.calculateRiskScore(factors);

        // 决策
        const decision = this.makeDecision(score, factors);

        return {
            score,
            decision,
            factors,
            timestamp: Date.now()
        };
    }

    // 设备风险检查
    private async checkDeviceRisk(deviceId: string): Promise<RiskFactor> {
        const device = await this.deviceService.getDevice(deviceId);

        // 新设备风险较高
        if (device.isNew) {
            return {
                type: 'device',
                score: 0.3,
                reason: 'New device detected',
                details: { deviceId, firstSeen: device.firstSeen }
            };
        }

        // 检查设备信誉
        if (device.reputation < 0.5) {
            return {
                type: 'device',
                score: 0.5,
                reason: 'Low device reputation',
                details: { deviceId, reputation: device.reputation }
            };
        }

        // 检查是否为模拟器/Root设备
        if (device.isEmulator || device.isRooted) {
            return {
                type: 'device',
                score: 0.7,
                reason: 'High-risk device (emulator/rooted)',
                details: { deviceId, isEmulator: device.isEmulator, isRooted: device.isRooted }
            };
        }

        return {
            type: 'device',
            score: 0,
            reason: 'Device is safe'
        };
    }

    // 用户行为分析
    private async analyzeUserBehavior(userId: string): Promise<RiskFactor> {
        // 获取用户历史行为
        const history = await this.getUserBehaviorHistory(userId);

        // 检查新用户
        if (history.transactionCount === 0) {
            return {
                type: 'behavior',
                score: 0.2,
                reason: 'New user'
            };
        }

        // 检查异常充值频率
        const recentTransactions = history.transactions.filter(t =>
            Date.now() - t.timestamp < 3600000 // 最近1小时
        );

        if (recentTransactions.length > 10) {
            return {
                type: 'behavior',
                score: 0.6,
                reason: 'Unusual transaction frequency',
                details: { count: recentTransactions.length }
            };
        }

        // 检查金额异常
        const avgAmount = history.averageAmount || 0;
        const currentTransaction = recentTransactions[0];

        if (currentTransaction && currentTransaction.amount > avgAmount * 10) {
            return {
                type: 'behavior',
                score: 0.5,
                reason: 'Unusually large transaction',
                details: { current: currentTransaction.amount, average: avgAmount }
            };
        }

        return {
            type: 'behavior',
            score: 0,
            reason: 'Normal behavior pattern'
        };
    }

    // 黑名单检查
    private async checkBlacklists(transaction: PaymentTransaction): Promise<RiskFactor> {
        const risks: string[] = [];

        // 检查用户黑名单
        if (this.blacklists.get('users')?.has(transaction.userId)) {
            risks.push('User in blacklist');
        }

        // 检查设备黑名单
        if (this.blacklists.get('devices')?.has(transaction.deviceId)) {
            risks.push('Device in blacklist');
        }

        // 检查IP黑名单
        if (this.blacklists.get('ips')?.has(transaction.ipAddress)) {
            risks.push('IP in blacklist');
        }

        // 检查支付卡黑名单
        if (transaction.cardHash && this.blacklists.get('cards')?.has(transaction.cardHash)) {
            risks.push('Card in blacklist');
        }

        if (risks.length > 0) {
            return {
                type: 'blacklist',
                score: 0.9,
                reason: 'Blacklist match',
                details: { risks }
            };
        }

        return {
            type: 'blacklist',
            score: 0,
            reason: 'No blacklist match'
        };
    }

    // 决策
    private makeDecision(score: number, factors: RiskFactor[]): RiskDecision {
        // 高风险:拒绝
        if (score >= 0.8) {
            return {
                action: 'reject',
                reason: 'High risk detected',
                requireAdditionalVerification: false
            };
        }

        // 中高风险:要求额外验证
        if (score >= 0.5) {
            return {
                action: 'verify',
                reason: 'Additional verification required',
                requireAdditionalVerification: true,
                verificationMethods: this.selectVerificationMethods(factors)
            };
        }

        // 正常:放行
        return {
            action: 'approve',
            reason: 'Low risk',
            requireAdditionalVerification: false
        };
    }
}

2. 反欺诈系统

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// 反欺诈检测
class FraudDetectionSystem {
    private detectors = new Map<string, FraudDetector>();
    private alerts = new Map<string, FraudAlert>();

    // 检测欺诈
    async detect(transaction: PaymentTransaction): Promise<FraudDetectionResult> {
        const detections: FraudIndicator[] = [];

        // 运行所有检测器
        for (const [name, detector] of this.detectors) {
            try {
                const result = await detector.detect(transaction);
                if (result.isFraud) {
                    detections.push({
                        detector: name,
                        confidence: result.confidence,
                        reasons: result.reasons,
                        evidence: result.evidence
                    });
                }
            } catch (error) {
                console.error(`Detector ${name} failed:`, error);
            }
        }

        // 综合判断
        const isFraud = detections.length > 0 &&
                       detections.some(d => d.confidence > 0.8);

        return {
            isFraud,
            confidence: this.calculateConfidence(detections),
            indicators: detections,
            timestamp: Date.now()
        };
    }

    // 速度检测(检测短时间内大量交易)
    class VelocityDetector implements FraudDetector {
        private timeWindow = 300000; // 5分钟
        private maxTransactions = 5;

        async detect(transaction: PaymentTransaction): Promise<DetectionResult> {
            // 获取时间窗口内的交易
            const recentTransactions = await this.getRecentTransactions(
                transaction.userId,
                this.timeWindow
            );

            if (recentTransactions.length >= this.maxTransactions) {
                return {
                    isFraud: true,
                    confidence: 0.9,
                    reasons: [`Too many transactions in ${this.timeWindow/1000} seconds`],
                    evidence: {
                        transactionCount: recentTransactions.length,
                        timeWindow: this.timeWindow
                    }
                };
            }

            return { isFraud: false, confidence: 0 };
        }
    }

    // 地理位置异常检测
    class GeoAnomalyDetector implements FraudDetector {
        async detect(transaction: PaymentTransaction): Promise<DetectionResult> {
            // 获取用户常用位置
            const usualLocations = await this.getUserUsualLocations(transaction.userId);

            // 检查当前位置是否异常
            const currentLocation = {
                country: transaction.country,
                city: transaction.city
            };

            const isUnusual = !usualLocations.some(loc =>
                loc.country === currentLocation.country &&
                loc.city === currentLocation.city
            );

            if (isUnusual) {
                // 检查是否可能(旅行距离)
                const lastTransaction = await this.getLastTransaction(transaction.userId);
                if (lastTransaction) {
                    const distance = this.calculateDistance(
                        lastTransaction.location,
                        currentLocation
                    );

                    // 短时间内移动距离过远
                    const timeDiff = Date.now() - lastTransaction.timestamp;
                    if (distance > 1000 && timeDiff < 3600000) { // 1000km in 1 hour
                        return {
                            isFraud: true,
                            confidence: 0.8,
                            reasons: ['Impossible travel detected'],
                            evidence: { distance, timeDiff }
                        };
                    }
                }

                return {
                    isFraud: true,
                    confidence: 0.5,
                    reasons: ['Unusual location'],
                    evidence: { currentLocation, usualLocations }
                };
            }

            return { isFraud: false, confidence: 0 };
        }
    }
}

隐私与合规

1. GDPR 合规

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// GDPR 合规管理
class GDPRComplianceManager {
    // 数据处理同意管理
    async recordConsent(userId: string, consents: ConsentRecord): Promise<void> {
        // 保存同意记录
        await this.db.consents.insert({
            userId,
            timestamp: Date.now(),
            consents,
            version: '1.0',
            ipAddress: consents.ipAddress
        });

        // 更新用户状态
        await this.db.users.update(userId, {
            gdprConsent: true,
            consentDate: new Date()
        });
    }

    // 数据访问请求(DSAR)
    async handleDataAccessRequest(userId: string): Promise<UserDataReport> {
        // 收集所有用户数据
        const data = await this.collectUserData(userId);

        // 生成报告
        return {
            userId,
            generatedAt: new Date(),
            dataCategories: this.categorizeData(data),
            data,
            sources: await this.getDataSources(userId),
            thirdParties: await this.getThirdPartySharing(userId)
        };
    }

    // 数据删除请求(被遗忘权)
    async handleDeletionRequest(userId: string): Promise<DeletionResult> {
        const deleted: string[] = [];
        const failed: string[] = [];

        // 需要删除的数据表
        const tables = [
            'users',
            'profiles',
            'transactions',
            'game_data',
            'activity_logs',
            'communications'
        ];

        for (const table of tables) {
            try {
                // 匿名化而非删除(保留审计记录)
                await this.db[table].updateMany(
                    { userId },
                    {
                        $set: {
                            anonymized: true,
                            anonymizedAt: new Date(),
                            // 清除敏感字段
                            email: null,
                            phoneNumber: null,
                            realName: null,
                            address: null
                        }
                    }
                );
                deleted.push(table);
            } catch (error) {
                failed.push(table);
            }
        }

        return {
            userId,
            requestedAt: new Date(),
            deleted,
            failed,
            retentionPeriod: '30 days for audit purposes'
        };
    }

    // 数据可携带权
    async handleDataPortabilityRequest(userId: string): Promise<DataExport> {
        // 收集数据
        const data = await this.collectUserData(userId);

        // 生成 JSON 格式
        const jsonData = JSON.stringify(data, null, 2);

        // 生成 CSV 格式
        const csvData = this.convertToCSV(data);

        return {
            userId,
            exportedAt: new Date(),
            formats: {
                json: jsonData,
                csv: csvData
            },
            size: {
                json: jsonData.length,
                csv: csvData.length
            }
        };
    }

    // 数据处理记录
    async logProcessingActivity(
        activity: ProcessingActivity
    ): Promise<void> {
        await this.db.processingLog.insert({
            ...activity,
            timestamp: Date.now(),
            legalBasis: this.determineLegalBasis(activity)
        });
    }
}

2. COPPA 合规(儿童隐私)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
// COPPA 合规管理
class COPPAComplianceManager {
    private parentalConsentCache = new Map<string, ConsentRecord>();

    // 验证年龄
    async verifyAge(userId: string, birthDate: Date): Promise<AgeVerificationResult> {
        const age = this.calculateAge(birthDate);

        if (age < 13) {
            // 需要父母同意
            const hasConsent = await this.checkParentalConsent(userId);

            if (!hasConsent) {
                return {
                    verified: false,
                    age,
                    requiresParentalConsent: true,
                    reason: 'User under 13 requires parental consent'
                };
            }
        }

        return {
            verified: true,
            age,
            requiresParentalConsent: false
        };
    }

    // 获取父母同意
    async requestParentalConsent(userId: string): Promise<ParentalConsentRequest> {
        const requestId = this.generateId();

        // 创建同意请求
        const request = {
            id: requestId,
            userId,
            status: 'pending',
            createdAt: Date.now(),
            expiresAt: Date.now() + 30 * 24 * 3600000 // 30天
        };

        await this.db.parentalConsentRequests.insert(request);

        // 发送验证邮件给父母
        await this.sendConsentEmail(request);

        return request;
    }

    // 验证父母同意
    async verifyParentalConsent(
        requestId: string,
        verificationCode: string
    ): Promise<VerificationResult> {
        const request = await this.db.parentalConsentRequests.findOne({ id: requestId });

        if (!request || request.status !== 'pending') {
            return { success: false, reason: 'Invalid or expired request' };
        }

        if (Date.now() > request.expiresAt) {
            return { success: false, reason: 'Request expired' };
        }

        // 验证码验证
        if (request.verificationCode !== verificationCode) {
            return { success: false, reason: 'Invalid verification code' };
        }

        // 记录同意
        const consent: ConsentRecord = {
            userId: request.userId,
            type: 'parental',
            grantedAt: Date.now(),
            method: 'email',
            ipAddress: request.ipAddress
        };

        await this.recordConsent(request.userId, consent);

        // 更新请求状态
        await this.db.parentalConsentRequests.update(
            { id: requestId },
            { status: 'verified', verifiedAt: Date.now() }
        );

        return { success: true };
    }

    // 限制数据收集(针对儿童)
    filterDataForMinor(data: UserData): UserData {
        // 只保留必要信息
        return {
            userId: data.userId,
            username: data.username,
            // 不收集:真实姓名、地址、电话等
            avatar: data.avatar,
            createdAt: data.createdAt
        };
    }
}

总结

游戏出海支付与合规的核心要点:

  1. 多渠道支付:全球主流支付方式 + 本地化支付
  2. 实时风控:设备指纹、行为分析、黑名单
  3. 反欺诈:速度检测、地理位置异常、机器学习
  4. 隐私合规:GDPR、COPPA 等法规要求
  5. 数据保护:加密存储、访问控制、审计日志

构建安全合规的支付系统是游戏出海的重要保障。


相关工具: