walkweltech/laravel-otp

使用一次性密码(otp)来保障你的laravel路由安全。

v3.0.5 2020-10-05 10:07 UTC

This package is auto-updated.

Last update: 2024-09-05 20:00:25 UTC


README

这是一个对 原始版本 的分支,因为在起始阶段原始版本不支持Laravel 8。此外,计划将新功能添加到这个分支中。

Latest Version on Packagist Software License Build Status StyleCI Quality Score Code Coverage Total Downloads

此包允许您通过一次性密码访问(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 渠道,或者您的通知渠道期望的方法不同于 mailsms,您可以注册自己的方法,如下所示

// 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

SymfonyInsight