Laravel 接口开发中的验证码注册

验证码类

首先将验证码接口平台的配置项放进配置文件中,如果你有其他三方平台,那么就放在一起。假设项目的三方平台的配置文件命名为 config/param.php

return [
    /*
    * 短信
    */
    'sms' => [
        'account'  => '账号',
        'password' => '密码',
        'prefix'   => '【learnKu】',// 前缀
        '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) {
                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
        ];
    }
}
本作品采用《CC 协议》,转载必须注明作者和本文链接

简洁略带风骚

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 2

有两个疑惑:
1.验证码保存到缓存中的时候做md5加密的目的是什么?
2.验证码保存到缓存中的时候做了md5加密,在验证的时候没有做md5,这样应该验证不通过吧?

2个月前 评论
php_yt (楼主) 2个月前

短信发送频繁限制的,可以用 Redis 缓存来处理。

2个月前 评论
php_yt (楼主) 2个月前

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!