cuongnd88 / otp-auth
Laravel OTP 身份验证(一次性密码)
1.3
2021-06-17 03:42 UTC
Requires
- php: ^7.2.5
Requires (Dev)
- mockery/mockery: ~1.3.1
- phpunit/phpunit: 7.*
README
此包允许您使用一次性密码访问(OTP)进行身份验证。
示例用法
Route::get("/notify", function(){ return App\Models\User::find(1)->notify(new App\Authentication\SendOtp('mail', 4, 10)); }); Route::get("/auth-otp/{otp}", function(){ return App\Models\User::authByOtp(request()->otp, '84905.......'); }); Route::get("/check-otp/{otp}", function(){ return App\Models\User::find(1)->checkOtp(request()->otp); });
内容
安装
1- 将包添加到依赖项中。
$ composer require cuongdinhngo/otp-auth
2- 运行命令
php artisan auth:otp {ClassName}
示例
php artisan auth:otp Authentication/SendOtp
SendOtp 类和 HasOtpAuth 特性在 app/Authentication 目录下自动生成。
CreateNotificationsTable 类也在 app/database/migrations 中自动生成。
3- 应用迁移
它将创建一个名为 notifications 的表来存储生成的 OTP 信息。
$ php artisan migrate
使用
生成 OTP
您可以通过电子邮件或短信生成 OTP
Route::get("/notify", function(){ return App\Models\User::find(1)->notify(new App\Authentication\SendOtp(['mail', 'nexmo'])); });
此包允许您更改 OTP 长度和有效期
Route::get("/notify", function(){ $length = 4; $liftime = 10; //minutes return App\Models\User::find(1)->notify(new App\Authentication\SendOtp(['mail', 'nexmo']), $length, $liftime); });
OTP 默认长度:默认长度为 6。
OTP 默认有效期:默认有效期为 1 分钟。
以下是自动生成 SentOTP 类的详细信息
<?php namespace App\Authentication; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification; use Cuongnd88\DeliveryChannel\Messages\TwilioMessage; class SendOtp extends Notification { use Queueable; protected $defaultChannels = ['database']; protected $otp; protected $lifeTime; const OPT_LIFETIME = 1; const OPT_LENGTH = 6; /** * Construct * * @param array|string $channels * @param integer|string $otpLength * @param integer|string $lifeTime */ public function __construct($channels = null, $otpLength = null, $lifeTime = null) { $this->otp = $this->generateOtp($otpLength ?? self::OPT_LENGTH); $this->lifeTime = $lifeTime ?? self::OPT_LIFETIME; $this->defaultChannels = $this->verifyChannels($channels); } /** * Get the notification's delivery channels. * * @param mixed $notifiable * @return array */ public function via($notifiable) { return $this->defaultChannels; } /** * Get the mail representation of the notification. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { return (new MailMessage) ->line('Your OTP is '.$this->otp) ->line('Thank you for using our application!'); } /** * Get the array representation of the notification. * * @param mixed $notifiable * @return array */ public function toArray($notifiable) { return [ 'otp' => $this->otp, 'expired_at' => now()->addMinutes($this->lifeTime)->toDateTimeString(), ]; } /** * Get the Nexmo / SMS representation of the notification. * * @param mixed $notifiable * * @return mixed */ public function toTwilio($notifiable) { return (new TwilioMessage) ->to("+8439xxxxxxx") ->from("+xxxxxxxxxx") ->body('OTP AUTH is '.$this->otp); } /** * Generate OTP * * @param integer|string $n * * @return string */ public function generateOtp($n) { $generator = "09xxxxxxx"; $result = ""; for ($i = 1; $i <= $n; $i++) { $result .= substr($generator, (rand()%(strlen($generator))), 1); } return $result; } /** * Verify channels * * @param string|array $channels * * @return array */ public function verifyChannels($channels) { if ($channels && is_array($channels)) { return array_merge($this->defaultChannels, $channels); } if ($channels && is_string($channels)) { array_push($this->defaultChannels, $channels); } return $this->defaultChannels; } }
toTwilio:此方法通过导入 delivery-channels 实现。
验证 OTP
通过您配置的方法发送 OTP 后,您可以通过调用 authByOtp 进行身份验证
Route::get("/auth-otp/{otp}", function(){ return App\Models\User::authByOtp(request()->otp, '84905123456'); });
根据您的凭证,您可能可以使用电子邮件或电话号码进行身份验证
设置凭证
在这种情况下,您可以应用 User 模型,它必须使用 HasOtpAuth 特性
. . . . use App\Authentication\HasOtpAuth; class User extends Authenticatable { use Notifiable; use HasOtpAuth; protected $credential = 'mobile'; . . . .
让我们更详细地看看 HasOtpAuth 特性
<?php namespace App\Authentication; trait HasOtpAuth { /** * Check OTP * * @return bool */ public function checkOtp($otp) { $authenticator = $this->otp(); return $this->validateOtp($authenticator, $otp); } /** * Get OTP data * * @return \Illuminate\Notifications\DatabaseNotification */ public function otp() { return $this->notifications() ->where('type', 'LIKE', '%SendOtp%') ->whereNull('read_at') ->first(); } /** * Validate OTP * * @param \Illuminate\Notifications\DatabaseNotification $authenticator * @param mixed $otp * * @return void */ public function validateOtp($authenticator, $otp) { $result = false; if (is_null($authenticator)) { return response()->json($result,200); } if ($authenticator && now()->lte($authenticator->data['expired_at']) && $authenticator->data['otp'] == $otp ) { $result = true; } $authenticator->markAsRead(); return response()->json($result,200); } /** * Authenticate by OTP * * @param string $otp * @param string $credentialValue * @return void */ public static function authByOtp($otp, $credentialValue) { $model = new static; $credentialName = property_exists($model,'credential') ? $model->credential : 'email'; $authenticator = $model->where($credentialName, '=', $credentialValue)->first(); if (is_null($authenticator)) { return response()->json(false,200); } $authenticator = $authenticator->notifications() ->where('type', 'LIKE', '%SendOtp%') ->whereNull('read_at') ->first(); return $model->validateOtp($authenticator, $otp); } }
基本识别
在某些情况下,您只需识别正确的访问权限,可能需要执行 checkOtp 方法
Route::get("/check-otp/{otp}", function(){ return auth()->user->checkOtp(request()->otp); });
演示
这是演示源代码。 Laravel Colab
致谢
- Ngo Dinh Cuong