Laravel 介面開發中的驗證碼註冊

php_yt發表於2020-03-11

驗證碼類

首先將驗證碼介面平臺的配置項放進配置檔案中,如果你有其他三方平臺,那麼就放在一起。假設專案的三方平臺的配置檔案命名為 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 協議》,轉載必須註明作者和本文連結

相關文章