getConfig(); if (!$config['enabled']) { return ['success' => false, 'message' => '短信服务未启用']; } // 生成6位验证码 $code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT); // 存储验证码 $cacheKey = "sms_code:{$phone}:{$type}"; Cache::put($cacheKey, [ 'code' => $code, 'expires_at' => now()->addMinutes($expireMinutes)->timestamp, ], now()->addMinutes($expireMinutes + 5)); // 调用阿里云短信 if ($config['driver'] === 'aliyun') { return $this->sendAliyunSms($phone, $code, $type, $config); } // 模拟模式(开发环境) \Log::info("SMS Code [{$type}] for {$phone}: {$code}"); return [ 'success' => true, 'message' => '验证码已发送(模拟模式)', 'data' => ['code' => $code], // 开发环境返回验证码 ]; } /** * 验证验证码 */ public function verifyCode(string $phone, string $code, string $type = 'login'): bool { $cacheKey = "sms_code:{$phone}:{$type}"; $data = Cache::get($cacheKey); if (!$data) { return false; } if ($data['expires_at'] < now()->timestamp) { Cache::forget($cacheKey); return false; } if ($data['code'] !== $code) { return false; } // 验证成功后删除 Cache::forget($cacheKey); return true; } /** * 获取短信配置 */ public function getConfig(): array { $cacheKey = 'sms_service_config'; return Cache::remember($cacheKey, 3600, function () { return [ 'enabled' => SystemConfig::getValue('sms', 'enabled', false), 'driver' => SystemConfig::getValue('sms', 'driver', 'aliyun'), 'access_key_id' => SystemConfig::getValue('sms', 'access_key_id', ''), 'access_key_secret' => SystemConfig::getValue('sms', 'access_key_secret', ''), 'sign_name' => SystemConfig::getValue('sms', 'sign_name', ''), 'template_codes' => SystemConfig::getValue('sms', 'template_codes', []), ]; }); } /** * 阿里云短信发送 */ private function sendAliyunSms(string $phone, string $code, string $type, array $config): array { $templateCode = $this->getTemplateCode($type, $config['template_codes']); if (!$templateCode) { return ['success' => false, 'message' => '未配置短信模板']; } try { $params = [ 'PhoneNumbers' => $phone, 'SignName' => $config['sign_name'], 'TemplateCode' => $templateCode, 'TemplateParam' => json_encode(['code' => $code]), ]; // 阿里云 OpenAPI 签名 $signResult = $this->aliyunSign($config['access_key_id'], $config['access_key_secret'], $params); $response = \Illuminate\Support\Facades\Http::withHeaders([ 'Content-Type' => 'application/x-www-form-urlencoded', ])->asForm()->post('https://dysmsapi.aliyuncs.com/', array_merge($params, $signResult)); $result = $response->json(); if (($result['Code'] ?? '') === 'OK') { return ['success' => true, 'message' => '发送成功']; } return ['success' => false, 'message' => $result['Message'] ?? '发送失败']; } catch (\Exception $e) { \Log::error('阿里云短信发送失败: ' . $e->getMessage()); return ['success' => false, 'message' => '短信发送失败']; } } /** * 获取模板代码 */ private function getTemplateCode(string $type, array $templates): ?string { $map = [ 'login' => $templates['login'] ?? null, 'reset_password' => $templates['reset_password'] ?? $templates['reset'] ?? null, 'pair' => $templates['pair'] ?? $templates['login'] ?? null, ]; return $map[$type] ?? null; } /** * 阿里云 API 签名 */ private function aliyunSign(string $accessKeyId, string $accessKeySecret, array $params): array { $params['AccessKeyId'] = $accessKeyId; $params['Format'] = 'JSON'; $params['SignatureMethod'] = 'HMAC-SHA1'; $params['SignatureVersion'] = '1.0'; $params['SignatureNonce'] = uniqid(); $params['Timestamp'] = gmdate('Y-m-d\TH:i:s\Z'); $params['Version'] = '2017-05-25'; ksort($params); $stringToSign = 'POST&%2F&' . urlencode(http_build_query($params, '', '&', PHP_QUERY_RFC3986)); $signature = base64_encode( hash_hmac('sha1', $stringToSign, $accessKeySecret . '&', true) ); $params['Signature'] = $signature; return $params; } }