首先将验证码接口平台的配置项放进配置文件中,如果你有其他三方平台,那么就放在一起。假设项目的三方平台的配置文件命名为 config/param.php
return [
/*
* 短信
*/
'sms' => [
'account' => '账号',
'password' => '密码',
'prefix' => '【csdn】',// 前缀
'suffix' => '',// 后缀
'ttl' => 5,// 过期时间
'template' => [
'code' => '您的验证码是{code},请在10分钟内填写。' //模板
]
],
...
];
编写一个验证码类 Sms
,你可以将它放在 app/Service
目录下(目录随意)。
class Sms
{
const URL = '短信平台接口';
/*
* 发送短信验证码
*
* $mobile 手机号
* $type 场景 login|signUp|editMobile|forgetPassword
* return true|errorMsg
*/
public static function sendCode($mobile,$type='login')
{
// 生成 code
if( app()->environment == 'production' ){
// N 分钟内发送频繁限制 这里选择数据库的目的是方便记录异常和统计 也可以使用任何存储介质
$count = DB::table('sms')->where('mobile',$mobile)->where('send_time','gt',time()-300)->count();
if( $count >=3 ){ return '您发送短信太频繁,请稍后再试';}
// 一天内发送总数限制
$count = Db::table('sms')->where('mobile', $mobile)->where('send_time', 'gt', time() - 24 * 60 * 60)->count();
if( $count >= 20 ){ return '您今天发送短信太频繁,请以后再试';}
//生成验证码
$code = rand(100000, 999999);
}else{
$code = 123456;
}
// 替换短信模板
$content = str_replace('{code}',$code,config('param.sms.templete.code'));
// 发送 测试环境返回 true
$ret = app()->environment != 'production' ? true : self::send($mobile,$content);
// 保存发送结果 无论发送成功 Or 失败
DB::table('sms')->insert([
'mobile' => $mobile,
'type' => $type,
'status' => $ret === true ? 1 : 0; //成功或失败
'content' => $content,
'send_time' => time(),
'sms_ret_msg' => strval($ret) //true转成1
]);
// 存储验证码 用于效验
cache()->set('sms:' . $type . ':' . $mobile, md5($code), config('param.sms.ttl'));
// 返回
retrun $ret;
}
/*
* 请求短信平台接口发送短信
* return true|errorMsg
*/
pubic static function send($mobile,$content)
{
$config = config('param.sms');
...
if( $code == xxx ){ return true; }
return empty($message) ? '发送失败' : $message;
}
/*
* 验证短信验证码
* $code md5(code)
* return true|errorMsg
*/
public static function check($mobile,$type,$code)
{
$key = 'sms:' . $type . ':' . $mobile;
$sms_code = cache($key);
if (!$sms_code) { return '请先发送短信验证码'; }
if ($sms_code != $code) { return '验证码错误'; }
// 销毁验证码
cache()->delete($key);
return true;
}
}
class PublicController extends Controller
{
public function sendSms(Request $request)
{
$post = $request->only(['mobile', 'type']);
$validator = Validator::make($post, [
'mobile'=> 'required|regex:/^1[3456789]{1}\d{9}$/',
'type'=> 'required|in:login,signUp,editMobile,forgetPassword'
]);
extract($post);
if ($validator->fails()) {
return // $validator->errors()
}
if ($type == 'signUp' || $type == 'editMobile') {
if (User::where('mobile', '=', $mobile)->first()) {
return // '该手机号已注册'
}
}
if ($type == 'forgetPassword') {
if (!User::where('mobile', '=', $mobile)->first()) {
return // '手机号未注册'
}
}
$result = Sms::sendCode($mobile, $type);
if ($result !== true) {
return // $result
}
return // '发送成功'
}
}
class AuthController extends Controller
{
public function signUp(Request $request)
{
$post = $request->only(['mobile', 'code', 'password', 'nickname']);
$validator = Validator::make($post, [
'mobile' => 'required|unique:users|regex:/^1[3456789]{1}\d{9}$/',
'code' => 'required',
'password' => 'required|alpha_num|size:32',
'nickname' => 'max:11',
]);
if ($validator->fails()) {
return //error
}
$ret = Sms::check($post['mobile'], 'signUp', $post['code']);
if ($ret !== true) {
return //$ret
}
$post['password'] = bcrypt($post['password']);
$post['status'] = 1;
...
DB::beginTransaction();
try{
$user = User::create($post);
// 其他操作
$ret = ...
if( !$ret ){
DB::rollBack();
return // error
}
$token = auth()->login($user);
}catch (\Exception $e) {
DB::rollBack();
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
return // '注册失败'
}
return // $this->respondWithToken($token);
}
/**
* Get the token array
*
* @param string $token
*
* @return array
*/
protected function respondWithToken($token)
{
return [
'username' => auth()->user()->username,
'access_token' => $token,
'token_type' => 'Bearer',
'expires_in' => auth()->factory()->getTTL() * 60 * 12
];
}
}