我使用的是阿里云的短信包。
如果是让我们直接写短信扩展发送的话,工作量是非常大的,所以,我使用的是外部扩展包
去packagist中搜索sms
我使用的是这一个
安装命令
composer require overtrue/easy-sms
这是一款满足你的多种发送需求的短信发送组件,支持多家平台的手机短信组件
首先,第一时间去申请阿里云短信签名和模板(大坑比来着)
短信模板
然后去使用下载的类库把
use Overtrue\EasySms\EasySms;
$config = [
// HTTP 请求的超时时间(秒)
'timeout' => 5.0,
// 默认发送配置
'default' => [
// 网关调用策略,默认:顺序调用
'strategy' => \Overtrue\EasySms\Strategies\OrderStrategy::class,
// 默认可用的发送网关
'gateways' => [
'aliyun',
],
],
// 可用的网关配置
'gateways' => [
'errorlog' => [
'file' => '/tmp/easy-sms.log',
],
'aliyun' => [
'access_key_id' => '',//阿里云的access_key_id
'access_key_secret' => '',//阿里云的access_key_secret
'sign_name' => '',//阿里云的签名
],
//...
],
];
$easySms = new EasySms($config);
$easySms->send(13188888888, [
'template' => 'SMS_001',//短信模板名
'data' => [
'code' => 6379//这里可以随机生成数
],
]);
值得注意的是,阿里云的access_key_id和access_key_secret要使用子用户组的,不能使用主组的,因为很危险
然后,去创建一个子用户
创建成功后
还需要给这个用户权限
添加了权限后就可以使用这个用户来调用API了
一般情况下,是不是要用到手机验证的地方非常多?
所以,我们可以将手机验证码类拆分来。
首先,先将发生验证码的配置信息拆分出来
1.在config配置目录下新建一个配置文件,里面存放的是发生验证码的配置信息
代码:
//短信发送配置信息
return $config = [
// HTTP 请求的超时时间(秒)
'timeout' => 5.0,
// 默认发送配置
'default' => [
// 网关调用策略,默认:顺序调用
'strategy' => \Overtrue\EasySms\Strategies\OrderStrategy::class,
// 默认可用的发送网关
'gateways' => [
'aliyun',
],
],
// 可用的网关配置
'gateways' => [
'errorlog' => [
'file' => '/tmp/easy-sms.log',
],
'aliyun' => [
'access_key_id' => env('SMS_AK'),
'access_key_secret' => env('SMS_SK'),
'sign_name' => '小信PHP',//阿里云签名的名字
],
//...
],
//短信模板
'template' => 'SMS_224341459',//模板名
];
里面的env(‘SMS_AK’)是什么意思呢?
由于,如果我们把代码放到GitHub里面,这个配置文件也会放到上面,那么,这不是暴露了我的秘钥了吗?所以,我把它放在.env文件中,因为.env文件是不会被发布到GitHub上面的
所以,env(‘SMS_AK’)被我放到了.env中,来看看
配置文件处理好后,就是来处理控制验证码的发送了
竟然说了手机验证码的方式在很多地方都会用到,那么就来使用事件
使用了事件,可以在我们需要的地方直接去调用它就好了
事件的注册在app\Providers\EventServiceProvider.php中,去$listen数组里面来注册一个事件,
这里定义一个SendSms事件,值得注意的是事件名SendSms要和SendSmsListener监听者名字不一样才可以
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
‘App\Events\SendSms’ => [
‘App\Listeners\SendSmsListener’,
],
];
定义好事件后,去执行添加事件命令,这个命令会自动检测事件文件,如果存在没有添加的事件文件,就会自动帮我生成事件文件
php artisan event:generate
执行该命令后,会在app\Listeners监听者目录和app\Events事件目录生成两个文件
因为我们定义的事件里面定义了监听者
所以,到时候是会触发监听者的,所以,我们把代码写在监听者文件里面
public function handle(SendSms $event)
{
//发送验证码到手机
$config = config('sms');
$easySms = new EasySms($config);
//随机生成验证码
$code = mt_rand(1000, 9999);
//缓存验证码
Cache::put('phone_code_' . $event->phone, $code, now()->addMinutes(5));
try {
$easySms->send($event->phone, [
'template' => $config['template'],
'data' => [
'code' => $code,
],
]);
} catch (\Exception $e) {
return $e->getExceptions();
}
}
那么代码里面的$event是哪里来的呢?就是刚刚我们生成了事件,
这个属性就是我们在调用事件的时候传递给它的
控制器文件BindController:
/*
* 获取手机验证码
*/
public function phoneCode(Request $request)
{
$request->validate([
'phone' => 'required|regex:/^1[3-9]\d{9}$/'
]);
//发送短信事件
SendSms::dispatch($request->input('phone'));
return $this->response->noContent();
}
确认验证码
/*
* 更新手机号
*/
public function updatePhone(Request $request)
{
//更新用户手机号
$user = auth('api')->user();//获取用户对象
$user->phone = $request->input('phone');//获取用户输入的邮箱
$user->save();//保存邮箱到数据库
return $this->response->noContent();
}
???,那么,这个确认验证码的验证去哪里了呢?
由于用到确认验证码的地方非常多,所以,我需要中间件来使用它,
因为,如果连中间件都过不了,也就进不来我们的控制器方法了。
那么,是如何让中间件在控制器中生效的呢?(以前写过在路由中)
来,写一个构造方法,每次执行进来控制器都去执行一下控制器
public function __construct()
{
//使用路由中间件
$this->middleware(['check.phone.code'])->only(['updatePhone']);
}
中间件是需要在app\Http\Kernel.php中注册才可以使用,check.phone.code这个名字也是在里面注册的
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'check.permission' => \App\Http\Middleware\CheckPermission::class,//用户权限中间件
'check.phone.code' => \App\Http\Middleware\CheckPhoneCode::class,//手机号验证中间件
'check.email.code' => \App\Http\Middleware\CheckEmailCode::class,//邮箱验证中间件
];
好了,这样就可以发送验证码并且可以验证了