walkweltech / laravel-otp
使用一次性密码(otp)来保障你的laravel路由安全。
Requires
- php: ^7.2.5
- illuminate/database: ^7.0|^8.0
- illuminate/http: ^7.0|^8.0
- illuminate/notifications: ^7.0|^8.0
- illuminate/routing: ^7.0|^8.0
- illuminate/support: ^7.0|^8.0
- nesbot/carbon: ^2.35
Requires (Dev)
- illuminate/config: ^7.0|^8.0
- mockery/mockery: ~1.3.1
- phpunit/phpunit: 7.*
README
这是一个对 原始版本 的分支,因为在起始阶段原始版本不支持Laravel 8。此外,计划将新功能添加到这个分支中。
此包允许您通过一次性密码访问(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 walkweltech/laravel-otp;
2- 在您的 config/app.php
文件中注册包
只有当您的自动包发现功能关闭时才需要。
WalkwelTech\Otp\OtpServiceProvider::class,
3- 发布组件
发布一个迁移、两个视图和一个配置文件。
$ php artisan vendor:publish
4- 应用迁移
将创建一个名为 otp_tokens
的表来存储生成的令牌信息。
$ php artisan migrate
5- 注册路由
如果您计划使用 otp
中间件,则这些路由是必需的。
在您的 RouteServiceProvider 中,在 map
方法内追加以下行
// App\RouteServiceProvider@map: \WalkwelTech\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' => \WalkwelTech\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 WalkwelTech\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》是否存在。如果存在,则调用此方法以确定将使用哪个通知渠道来通知《notifiable》。
深入了解
公共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