erdemkeren / laravel-otp
使用一次性密码(OTP)来保护您的Laravel路由。
Requires
- php: ^8.0
- illuminate/database: ^8.0
- illuminate/http: ^8.0
- illuminate/notifications: ^8.0
- illuminate/routing: ^8.0
- illuminate/support: ^8.0
- nesbot/carbon: ^2.35
Requires (Dev)
- illuminate/config: ^8.0
- mockery/mockery: ~1.4.3
- phpunit/phpunit: 8.*
README
需要维护者!
我没有时间维护这个包,因此正在寻找维护者。我对放弃这个项目并建议替代包持开放态度。
Laravel OTP
此包允许您使用一次性密码(OTP)来保护您的资源。
示例用法
Route::get('secret', function (\Illuminate\Http\Request $request): string { $token = $request->otpToken(); $messages[] = "The otp token {$token} has {$token->timeLeft()} out of {$token->expiryTime()} seconds."; $token->refresh(); $messages[] = "The time left can be reset using the refresh method: {$token->timeLeft()}/{$token->expiryTime()}"; $token->extend(30); $messages[] = "The expiry time can be increased using the extend method: {$token->timeLeft()}/{$token->expiryTime()}"; $messages[] = "You can also invalidate the token immediately. Try refreshing the page ;)"; $request->otpToken()->invalidate(); return implode('<br>', $messages); })->middleware('auth', 'otp');
内容
安装
1- 将包添加到依赖项。
$ composer require erdemkeren/laravel-otp;
2- 在您的 config/app.php
文件中注册包
仅当您的自动包发现关闭时。
Erdemkeren\Otp\OtpServiceProvider::class,
3- 发布组件
发布一个迁移、两个视图和一个配置文件。
$ php artisan vendor:publish
4- 应用迁移
将创建一个名为 otp_tokens
的表来存储生成的令牌信息。
$ php artisan migrate
5- 注册路由
如果您计划使用 otp
中间件,则需要这些路由。
在您的 RouteServiceProvider 中,在 map
方法内追加以下行
// App\RouteServiceProvider@map: \Erdemkeren\Otp\OtpRoutes::register();
6- 注册路由中间件
在您的 App\Http\Kernel
中注册 otp 路由中间件。
/** * The application's route middleware. * * These middleware may be assigned to groups or used individually. * * @var array */ protected $routeMiddleware = [ // [...] 'otp' => \Erdemkeren\Otp\Http\Middleware\Otp::class, ];
配置
此包提供了一套方便的配置选项
password_generator: 密码生成器选项允许您决定使用哪种生成器实现来生成新密码。
可用内置选项:string, numeric 和 numeric-no-0。默认:string
table: 存储OTP令牌的表的名称。
默认:otp_tokens
expiry_time: 令牌的有效期(分钟)。
默认:15
default_channels: 令牌通知的默认通知通道。
使用
基本用法
配置完包的实例后,您可以使用内置的 otp
中间件别名来保护您的端点
Route::get('secret', function (Request $request): string { $request->otpToken()->refresh(); return 'The secret of immortality'; })->middleware('auth', 'otp');
此中间件将任何未认证的请求重定向到我们在安装过程中注册的 otp/create
端点
- 将使用配置的密码生成器生成密码。
- 将通过配置的通知渠道通知认证用户。
- 用户将看到一个表单来提交他们的密码。
- 您可以通过修改
resources/views/otp
目录下的create.blade.php
文件来更改视图的外观。 - 认证成功后,用户将被重定向回他们最初请求的原始路由。
- 重定向请求还将包含用户使用的
otpToken()
实例。
高级用法
添加通知渠道方法
如果您不使用 mail
通道,或者您的通知通道期望的方法不同于 mail
或 sms
,您可以注册自己的方法,如下所示
// AppServiceProvider::register(): TokenNotification::macro('AcmeSms', function () { // $this is TokenNotification class. return $this->notification->code; });
别忘了更改您的配置文件。
使用您自己的密码生成器
要添加自己的密码生成器实现,您可以在 Otp
服务上调用 addPasswordGenerator
方法,如下所示
// AppServiceProvider::register(): app('otp')->addPasswordGenerator('acme', function (int $length): string { return 'your_implementation'; });
如果您需要更多的功能,您也可以创建自己的密码生成器类
<?php namespace App\Acme\PasswordGenerators; use Erdemkeren\Otp\PasswordGeneratorInterface; class AcmePasswordGenerator implements PasswordGeneratorInterface { /** * Generate an acme password with the given length. * * @param int $length * @return string */ public function generate(int $length): string { return 'your implementation'; } }
您可以像之前的密码生成器一样注册您的密码生成器
// AppServiceProvider::register(): Otp::addPasswordGenerator('acme', AcmePasswordGenerator::class);
别忘了更改您的配置文件。
为每个可通知项确定OTP通道
Notification
类检查正在通知的 notifiable
中是否存在 otpChannels
。如果存在,则调用此方法以确定将使用哪个通知通道来通知可通知项。
深入知识
公共API由两个主要组件组成:OtpService
和通常由服务返回的 Token
。
OTP服务
如果您计划创建自己的API或基本功能不足以满足您的需求,您可以使用OTP服务API
检查给定令牌的有效性
$isTokenValid = Otp::check($authenticableId, $token);
设置密码生成器
Otp::setPasswordGenerator('string');
为给定用户创建新的令牌
$token = Otp::create(auth()->user(), $length = 6); // See what can be done with tokens below.
通过给定的明文密码从存储中检索现有令牌
$token = Otp::retrieveByPlainText(auth()->id(), $otpPassword); // See what can be done with tokens below.
通过给定的密文(令牌)从存储中检索现有令牌
$token = Otp::retrieveByCipherText(auth()->id(), $otpPassword); // See what can be done with tokens below.
更改服务的行为
该软件包附带一个 ServiceProvider
,它将OTP服务注册到您的应用程序容器中。
OTP协调对以下3个接口实现的调用方法。
- 密码生成器管理接口
- 加密器接口和
- 令牌接口
您可以为您的服务提供程序编写代码,并使用您的依赖项版本注册 OtpService
。
注意:由于令牌类使用静态调用,您必须发送您 TokenInterface
实现的完全限定名称。
令牌API
获取令牌的属性
public function authenticableId(); public function cipherText(): string; public function plainText(): ?string; // If you have just created the token, plain text will be accessable. If you retrieved it; it won't. public function createdAt(): Carbon; public function updatedAt(): Carbon; public function expiryTime(): int; public function expiresAt(): Carbon; public function timeLeft(): int; public function expired(): bool;
使令牌无效
public function revoke(): void; public function invalidate(): void;
例如
public function show(Request $request, $id) { if($request->input('revoke_session', false)) { $request->otpToken()->revoke(); } return view('heaven'); }
扩展或刷新令牌过期时间
// Extend the usage time of the token for the given seconds: public function extend(?int $seconds = null): bool; // Make the token function like it has just been created: public function refresh(): bool;
例如
$token = Otp::retrieveByCipherText( auth()->id(), $request->input('otp_token') ); if(! $token->expired()) { $token->refresh(); }
创建新的令牌
public static function create( $authenticableId, string $cipherText, ?string $plainText = null ): TokenInterface;
例如
$token = Token::create(1, 'foo', 'plain foo');
通过给定的属性从存储中检索令牌
确保您提供的属性将返回唯一的令牌。
public static function retrieveByAttributes(array $attributes): ?TokenInterface;
例如
$token = Token::retrieveByAttributes([ 'authenticable_id' => 1, 'cipher_text' => 'foo', ]);
将令牌转换为通知
public function toNotification(): Notification;
例如
$user->notify($token->toNotification());
变更日志
有关最近更改的更多信息,请参阅 变更日志
测试
$ composer test
致谢
- Hilmi Erdem KEREN
- Berkay Güre