阿里云短信验证码服务
文章目录
- 环境
- 背景
- 方法
- alibabacloud/dysmsapi-20170525
- alibabacloud/sdk (todo)
- alibabacloud/client
- 参考
环境
- Windows 11 家庭版
- PHP 8.2.12
背景
我们在日常生活中,经常会用到手机验证码短信。它可以大大提高安全性,证明当前操作的人确实是手机号的合法所有者,并且能防止批量自动化攻击。
本文以阿里云短信服务为例,介绍如何实现发送手机验证码短信。
方法
阿里云提供了短信服务(当然要花钱买),首先要获取以下信息:
- accessKeyId:
- accessKeySecret:
- SignName:短信的发送方(比如公司名称)
- TemplateCode:短信内容模板编号,类似
SMS_xxxxxx
应用需要安装阿里云SDK,才能调用阿里云的短信服务,下面以PHP为例介绍具体方法。
alibabacloud/dysmsapi-20170525
新建目录 test0821_1
,进入该目录(即项目根目录)。
首先要安装阿里云SDK的依赖包,运行:
composer require alibabacloud/dysmsapi-20170525 4.1.2
注:这里指定了版本 4.1.2
,经测试,假如不指定版本,实际也是 4.1.2
(在 composer.lock
文件里查看)。
在项目根目录下创建 test.php
文件:
<?phprequire_once __DIR__ . '/vendor/autoload.php';use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest;
use AlibabaCloud\Dara\Models\RuntimeOptions;
use Darabonba\OpenApi\Models\Config as DysmsapiConfig;
use Exception;$accessKeyId = 'xxxxxx';
$accessKeySecret = 'xxxxxx';try {$config = new DysmsapiConfig(["accessKeyId" => $accessKeyId,"accessKeySecret" => $accessKeySecret,"endpoint" => "dysmsapi.aliyuncs.com" // 显式设置endpoint]);$client = new Dysmsapi($config);$request = new SendSmsRequest(["phoneNumbers" => 'xxxxxx',"signName" => 'xxxxxx',"templateCode" => 'xxxxxx',"templateParam" => json_encode(['code' => '555666'])]);// 设置运行时选项$runtime = new RuntimeOptions([]);$runtime->ignoreSSL = true; // 未配置CA证书,临时忽略SSL验证// 发送短信$response = $client->sendSmsWithOptions($request, $runtime);if ($response->body->code === 'OK') {echo '发送成功!BizId: ' . $response->body->bizId . PHP_EOL;} else {echo "发送失败: " . $response->body->message . PHP_EOL;}
} catch (Exception $e) {echo $e->getMessage() . PHP_EOL;
}
注意:代码中有几处 xxxxxx
,需要替换成真实值:
- accessKeyId:
- accessKeySecret:
- PhoneNumbers:短信的接收方(手机号)
- SignName:短信的发送方(比如公司名称)
- TemplateCode:比如
SMS_xxxxxx
,这个东东是短信内容的模板,只不过有一些参数需要填充。本例中是一个发送验证码的短信,模板内容是:“您的验证码为:xxxxxx,请勿泄露于他人!”,其中的参数通过TemplateParam
来填充。
运行程序,就会给目标手机发送一条短信:
注:本例只是一个demo, accessKeyId
和 accessKeySecret
以明文形式直接放在了代码里。实际项目中,一般可以放到Secret里。
可见,验证码短信是短信模板 + 验证码,其中验证码的生成和校验,都是应用后端的行为,和阿里云以及运营商并没有关系。
- 验证码生成:本例中是应用后端hardcode了一个验证码,实际运行时,可以随机产生6位数字,然后要把它暂存起来,以便待会儿校验
- 验证码校验:用户收到验证码短信后,在应用里输入验证码,然后提交,后端拿到验证码后,和保存的验证码相比较,如果匹配,则校验成功,说明用户提供的手机号是真实有效的。
另外,阿里云网站上( https://next.api.aliyun.com/api-tools/sdk/Dysmsapi?version=2017-05-25&language=php-tea&tab=primer-doc
)提供的是一个类,经改编后如下:
<?php
require_once __DIR__ . '/vendor/autoload.php';use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest;
use AlibabaCloud\Dara\Models\RuntimeOptions;
use AlibabaCloud\Tea\Exception\TeaError;
use Darabonba\OpenApi\Models\Config as DysmsapiConfig;
use Exception;class AliyunSmsService {private $accessKeyId;private $accessKeySecret;private $client;public function __construct($accessKeyId, $accessKeySecret) {$this->accessKeyId = $accessKeyId;$this->accessKeySecret = $accessKeySecret;$this->initializeClient();}private function initializeClient() {try {$config = new DysmsapiConfig(["accessKeyId" => $this->accessKeyId,"accessKeySecret" => $this->accessKeySecret,"endpoint" => "dysmsapi.aliyuncs.com" // 显式设置endpoint]);$this->client = new Dysmsapi($config);} catch (Exception $e) {throw new Exception("初始化短信客户端失败: " . $e->getMessage());}}public function sendSms($phoneNumber, $signName, $templateCode, $templateParams = []) {if (empty($phoneNumber) || empty($signName) || empty($templateCode)) {return ['success' => false,'message' => '参数不完整'];}try {// 准备请求参数$request = new SendSmsRequest(["phoneNumbers" => $phoneNumber,"signName" => $signName,"templateCode" => $templateCode,"templateParam" => !empty($templateParams) ? json_encode($templateParams, JSON_UNESCAPED_UNICODE) : null]);// 设置运行时选项$runtime = new RuntimeOptions([]);$runtime->ignoreSSL = true; // 未配置CA证书,临时忽略SSL验证// 发送短信$response = $this->client->sendSmsWithOptions($request, $runtime);// 处理响应if ($response->body->code === 'OK') {return ['success' => true,'message' => '发送成功','bizId' => $response->body->bizId,'requestId' => $response->body->requestId];} else {return ['success' => false,'message' => $response->body->message,'code' => $response->body->code,'requestId' => $response->body->requestId];}} catch (TeaError $e) {return ['success' => false,'message' => 'TeaError: ' . $e->getMessage(),'code' => $e->getCode()];} catch (Exception $e) {return ['success' => false,'message' => 'Exception: ' . $e->getMessage(),'code' => $e->getCode()];}}
}// ==================== 使用示例 ====================// 配置信息 - 请替换为实际值
$config = ['accessKeyId' => 'xxxxxx','accessKeySecret' => 'xxxxxx','phoneNumber' => 'xxxxxx','signName' => 'xxxxxx', // 如:阿里云'templateCode' => 'xxxxxx', // 模板CODE
];try {// 创建实例$smsService = new AliyunSmsService($config['accessKeyId'], $config['accessKeySecret']);// 生成验证码$verificationCode = '234567';// 发送短信$result = $smsService->sendSms($config['phoneNumber'],$config['signName'],$config['templateCode'],['code' => $verificationCode] // 模板参数,根据实际模板调整);// 输出结果echo "发送结果: " . ($result['success'] ? '成功' : '失败') . "\n";echo "消息: " . $result['message'] . "\n";if ($result['success']) {echo "业务ID: " . $result['bizId'] . "\n";// 这里应该将验证码存储到Session或Redis中session_start();$_SESSION['sms_verification'] = ['code' => $verificationCode,'phone' => $config['phoneNumber'],'expire_time' => time() + 300 // 5分钟过期];} else {echo "错误代码: " . ($result['code'] ?? '未知') . "\n";}} catch (Exception $e) {echo "初始化失败: " . $e->getMessage() . "\n";
}// 打印详细结果(调试用)
echo "\n详细响应:\n";
print_r($result);
注:官网上的代码,貌似无法直接使用,有各种小毛病。上面的代码是结合官网和DeepSeek改编的。
alibabacloud/sdk (todo)
新建目录 test0821_2
,进入该目录(即项目根目录)。
首先要安装阿里云SDK的依赖包,运行:
composer require alibabacloud/sdk
然后代码和前面类似,但是我还没有搞定。。。总是各种报错。
alibabacloud/client
新建目录 test0821_3
,进入该目录,(即项目根目录)。
首先要安装阿里云SDK的依赖包,运行:
composer require alibabacloud/client
在项目根目录下创建 test.php
:
<?phprequire_once __DIR__ . '/vendor/autoload.php';use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;// 配置 AccessKey
$accessKeyId = 'xxxxxx'; //阿里云短信获取的accessKeyId
$accessKeySecret = 'xxxxxx'; //阿里云短信获取的accessKeySecrettry {// 初始化客户端AlibabaCloud::accessKeyClient($accessKeyId, $accessKeySecret)->regionId('cn-hangzhou') // 默认即可->asDefaultClient();// 发送短信$result = AlibabaCloud::rpc()->product('Dysmsapi')->version('2017-05-25')->action('SendSms')->method('POST')->host('dysmsapi.aliyuncs.com')->options(['query' => ['RegionId' => "cn-hangzhou",'PhoneNumbers' => "xxxxxx",'SignName' => "xxxxxx",'TemplateCode' => "xxxxxx",'TemplateParam' => json_encode(['code' => '123456']),],])->request();// 处理结果$result = $result->toArray();if ($result['Code'] === 'OK') {echo "发送成功!BizId: " . $result['BizId'];} else {echo "发送失败: " . $result['Message'];}} catch (ClientException $e) {echo $e->getErrorMessage() . PHP_EOL;
} catch (ServerException $e) {echo $e->getErrorMessage() . PHP_EOL;
}
注:DeepSeek说,这个方法使用的是阿里云旧版SDK,但仍然有很多应用场景,较为稳定。
参考
https://next.api.aliyun.com/api-tools/sdk/Dysmsapi
https://next.api.aliyun.com/api/Dysmsapi/2017-05-25/SendSms
https://help.aliyun.com/zh/sms/