metarush/otp-auth

使用一次性密码(通过电子邮件令牌)进行身份验证的库

v4.0.2 2022-06-12 15:13 UTC

This package is auto-updated.

Last update: 2024-09-24 20:09:39 UTC


README

使用一次性密码(OTP)通过电子邮件进行用户认证和登录。

安装

使用 composer 以 metarush/otp-auth 的形式安装

数据库设置

除了您通常的 username 和/或 email 列外,在您的用户表中创建以下列。

  • otpHash TEXT (255)
  • otpToken TEXT(12)
  • otpExpire INT (10)
  • rememberHash TEXT (255)
  • rememberToken TEXT (12)

注意:如果您想使用其他列名,只需在配置中设置即可。

示例用法

以下示例旨在以简单的方式展示库的功能。您不必按原样使用此实现。

_init.php

创建一个 _init.php 文件并将其包含在脚本顶部,放置以下内容。

初始化构建器

$builder = new MetaRush\OtpAuth\Builder;

定义 SMTP 服务器

$smtpServers = [
    0 => $builder->SmtpServer()
        ->setHost('host')
        ->setUser('user')
        ->setPass('pass')
        ->setPort(465)
        ->setEncr('TLS'),
    1 => $builder->SmtpServer()
        ->setHost('host2')
        ->setUser('user')
        ->setPass('pass')
        ->setPort(465)
        ->setEncr('TLS'),
    ];

您可以添加任意多个,库将自动故障转移。

使用最小配置初始化库

$auth = $builder->setDsn('mysql:host=localhost;dbname=foo')
    ->setServers($smtpServers)
    ->setAdminEmails(['admin@example.com'])
    ->setAppName('foo')
    ->setFromEmail('noreply@example.com')
    ->setUsernameColumn('email')
    ->setNotificationFromEmail('noreply@example.com')
    ->setTable('users')
    ->build();

注意:如果您想扩展 Auth 类并继续使用构建器,您可以将您的子类作为字符串传递给 build() 参数。例如 ->build('MyAuth');

如果通过 cookie 记住了用户名,则自动登录

if (!$auth->authenticated()) {
    $rememberedUsername = $auth->rememberedUsername();
    if (null !== $rememberedUsername)
        $auth->login($rememberedUsername);
}

login.php

创建一个 login.php 文件并放置以下内容。

<?php

include '_init.php';

if ($_POST) {
    $username = $_POST['email'];

    // check if username exists
    if (!$auth->userExist($username))
        exit('User does not exist');

    // remember username for next page (otp.php)
    setcookie('username', $username);

    // send OTP to user's email
    $otp = $auth->generateToken(5);
    $auth->sendOtp($otp, $username);

    // redirect to OTP page
    header('location: otp.php');
}

?>

<?php if ($auth->authenticated()): ?>

    You are already logged-in

<?php else: ?>

    <form method="post">
        Email: <input type="text" name="email" />
    </form>

<?php endif; ?>

otp.php

创建一个 otp.php 文件并放置以下内容。

<?php

include '_init.php';

if ($_POST) {
    $otp = $_POST['otp'];
    $username = $_COOKIE['username'];

    // remember username in browser if user wants to
    if (isset($_POST['remember']))
        $auth->remember($username);

    // check if OTP is valid
    if (!$auth->validOtp($otp, $username))
        exit('Invalid OTP');

    // login username
    $auth->login($username);

    echo 'OTP is valid';
    // redirect to your restricted page
}

?>

<?php if ($auth->authenticated()): ?>

    You are already logged-in

<?php else: ?>

    <form method="post">
        OTP: <input type="text" name="otp" />
        <br />
        <br />
        Remember? <input type="checkbox" name="remember" />
        <br />
        <br />
        <input type="submit" />
    </form>

<?php endif; ?>

logout.php

创建一个 logout.php 文件并放置以下内容。

<?php

include '_init.php';

// destroy user session
$auth->logout();

配置方法

您可以在 ->build(); 方法之前使用以下方法在构建器对象中

setAdminEmails(array);

将获取错误通知的管理员电子邮件数组

setAppName(string);

错误通知上您的应用的标签

setBody(string);

OTP 电子邮件的正文。如果您设置此值,则必须包括模板变量 {OTP}

默认值: {OTP}\r\n\r\n注意:此 OTP 有效期为 5 分钟

setCharacterPool(string);

令牌从中派生的字符池

默认值: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

setCookiePrefix(string);

metarush/otp-auth 使用的 Cookie 名称前缀

默认值: MROA_

setCookiePath(?string);

metarush/otp-auth 使用的 Cookie 路径

默认值: /

setDbPass(string);

用户表的数据库密码

setDbUser(string);

用户表的数据库用户名

setDsn(string);

用于连接到您的用户表的 PDO DSN

setEmailColumn(string);

存储用户电子邮件的表列

默认值: email

setFromEmail(string);

OTP 消息的发件人电子邮件

setFromName(string);

OTP 消息的发件人姓名

setNotificationFromEmail(string);

如果您通过 setAdminEmail() 设置了管理员电子邮件,则必须设置错误通知的 From Email

setOtpExpire(int);

OTP 过期时间(分钟)。如果您设置此值,请确保通过 setBody(string); 更改电子邮件消息以反映 OTP 过期时间。

默认值: 5

setOtpExpireColumn(string);

存储 OTP 过期的表列

默认值: otpExpire

setOtpHashColumn(string);

存储 OTP 哈希的表列

默认值: otpHash

setOtpTokenColumn(string);

存储 OTP 令牌的表列

默认值: otpToken

setRememberCookieExpire(int);

"记住我" Cookie 过期时间(秒)

默认值: 2592000(30 天)

setRememberHashColumn(string);

"记住我" 哈希的表列名

默认: rememberHash

setRememberTokenColumn(string);

用于查找“记住我”cookie的令牌的表列名

默认: rememberToken

setServers(array);

SmtpServer对象数组。参见上面的示例“定义SMTP服务器”

setSubject(string);

OTP电子邮件的主题

默认: 这是您的OTP

setTable(string);

用户名将进行身份验证的表

默认: users

setUsernameColumn(string);

存储用户名的表列名

默认: username

setUserIdColumn(string);

存储userId的表列名

默认: id

SMTP轮询模式

您可以使用轮询模式在发送OTP电子邮件时将负载分配到所有SMTP主机。

要启用轮询模式,您必须使用存储驱动程序来跟踪用于发送电子邮件的最后一个服务器。

可用的驱动程序及其配置

files

$driver = 'files';
$driverConfig = [
    'path' => '/var/www/example/emailFallbackCache/'
];

memcached

$driver = 'memcached';
$driverConfig = [
    'host'         => '127.0.0.1',
    'port'         => 11211,
    'saslUser'     => '',
    'saslPassword' => ''
];

注意:目前仅支持单个服务器/非分布式memcached。

redis

$driver = 'redis';
$driverConfig = [
    'host'      => '127.0.0.1',
    'port'      => 6379,
    'password'  => '',
    'database'  => 0
];

注意:如果可用,请使用memcached或redis,因为files不建议用于重负载。

在选择驱动程序后,在->build();方法之前,在构建对象中设置以下内容

->setRoundRobinMode(true)
->setRoundRobinDriver($driver)
->setRoundRobinDriverConfig($driverConfig)

服务方法

authenticated(): bool

检查用户是否已认证

generateToken(int $length): string

$length 您想要生成的令牌长度。

生成随机令牌

login(string $username, ?array $userData = []): void

以认证用户登录

$username 要登录的用户名

$userData 您定义的任意用户数据,例如firstName,email(可选)

logout(): void

注销用户并删除“记住我”cookie

remember(string $username, int $howLong = null): void

在浏览器中记住用户名登录

$username 要记住的用户名

$howLong 以秒为单位记住用户的时间。默认值为30天,除非在配置中使用了setRememberCookieExpire()

rememberedUsername(?string $cookie = null): ?string

如果有的话,通过cookie获取记住的用户名。

$cookie 如果为null,则使用默认cookie。

sendOtp(string $otp, string $username, bool $useNextSmtpHost = false, int $testLastServerKey = null): void

通过电子邮件将OTP发送给用户

$otp 要发送给用户的OTP。您可以使用generateToken()服务方法生成随机OTP。建议的OTP长度至少为8。

$username 要发送OTP的用户名

$useNextSmtpHost 如果您想在下次使用sendOtp()时使用相对于当前用户的下一个可用的SMTP主机,请将其设置为true。如果您上次发送的电子邮件到达缓慢,这很有用。例如,创建一个“重试”UI,然后使用sendOtp($otp, $username, true)使用下一个SMTP主机发送新的OTP。

userData(): array

如果通过login()参数设置,则返回任意用户数据

userExist(string $username): bool

检查用户是否存在

$username 要检查的用户名

validOtp(string $otp, string $username, ?string $testOtpToken = null): bool

验证OTP

$otp 要验证的OTP

$username 与OTP关联的用户名

otpExpired(string $username): bool

检查OTP是否已过期

$username 与OTP关联的用户名

userId(string $username): int

返回$username的userId

$username 获取userId的用户名

暴力保护

我们建议使用metarush/firewall库来实现登录暴力保护。