hichemtab-tech/tokens-validation

TokensValidation 是一个用于在 Web 应用程序中进行安全认证和授权的 PHP 库。它可以生成动态令牌以进行用户登录、密码重置和电子邮件确认。该库非常适合需要安全用户认证和授权的软件。

4.0.0 2024-03-27 22:06 UTC

README

Logo

TokensValidation

TokensValidation 是一个 PHP 库,旨在动态生成和验证认证和确认令牌。它非常适合需要安全用户认证和授权的 Web 应用程序和软件。该库生成的认证和确认令牌可用于登录用户、重置密码和确认电子邮件地址。

目录

  1. 安装
  2. 功能
  3. 使用方法
    1. 认证令牌
      1. 使用 Cookie
      2. 自己处理令牌
      3. 覆盖 Cookie 处理方法
    2. 指纹
    3. 确认令牌
      1. 通过 URL
      2. 通过输入
      3. WhatFor 字段
      4. 检查后删除
      5. 每期一个令牌
    4. 令牌生成器
    5. 令牌过期
    6. 邀请
    7. 在 Laravel 中
    8. 错误识别
  4. 许可

安装

ℹ️ 信息:本版本与 PHP 8 及以上版本兼容。如果您正在使用 PHP 7,则必须安装此库的 3.2.2 版本。

您可以通过运行以下命令使用 Composer 安装 TokensValidation 库

  composer require hichemtab-tech/tokens-validation

功能

  • 在浏览器关闭后无需密码进行用户认证
  • 生成带有过期延迟的自定义确认代码。
  • 创建邀请令牌以执行某些操作。
  • 使用灵活性
  • 安全与加密

使用方法

要使用此库,您首先需要通过调用以下方法设置数据库连接参数

<?php

use HichemtabTech\TokensValidation\TokensValidation;

require 'vendor/autoload.php';

TokensValidation::setDBHOST("localhost");
TokensValidation::setDBNAME("test");
TokensValidation::setDBUSER("root");
TokensValidation::setDBPASS("");

之后,您可以调用 prepare() 方法在数据库中创建必要的表

TokensValidation::prepare();

用户可以重复调用此代码,因为库将只执行必要的准备步骤,例如创建表,一次。之后,这些步骤将自动忽略,除非表不再存在。

认证令牌

认证令牌用于用户登录后进行用户认证。TokensValidation 可以生成和验证认证令牌。

TokensValidation 生成一个安全令牌,用于识别用户登录时发出的请求。此令牌还允许用户在关闭浏览器后利用 Cookie 再次登录,而无需再次输入密码。

该库提供三种处理认证令牌的方法

  • 使用 Cookie
  • 自己处理令牌
  • 覆盖 Cookie 处理方法

以下是一些使用 TokensValidation 处理认证令牌的示例

1-使用 Cookie

第一个示例是自动生成和验证

  • 要使用 Cookie 生成认证令牌,请调用以下方法
$authToken = TokensValidation::createNewAuthToken(
        userId: $uid,
        usingCookies: true
    );

// you can print $authToken for additional informations about the created token.

此方法为指定的用户 ID 生成新的认证令牌并将其保存到 Cookie 中。第二个参数指定是否使用 Cookie。

要检查认证令牌,请调用以下方法

$result = TokensValidation::checkAuthToken();
    if ($result->isValidationSucceed()) {
        // log in the user automatically,
        //for example :
        autoLogin($result->getUserId());
    }
    else{
        //throw an error or redirect to log in
    }

TokensValidation::checkAuthToken() 检查 Cookie 中的认证令牌并返回结果。如果验证成功,将生成新令牌并替换 Cookie 中的旧令牌。

检查令牌而不生成新令牌
$result = TokensValidation::checkAuthTokenWithoutRegenerate();

该行代码执行名为 TokensValidation::checkAuthTokenWithoutRegenerate() 的函数,该函数对令牌进行校验以确保其有效性,但不会生成新的令牌来替换旧的令牌。此次校验的目的是验证令牌是否仍然有效且未被篡改。如果令牌仍然有效,函数将返回成功结果,该结果将存储在变量 "$result" 中。

需要注意的是,此函数仅校验令牌的有效性而不进行生成。如果令牌无效或已过期,函数将返回错误或失败信息,指示用户必须重新登录以获取新的令牌。因此,此函数通过确保令牌仍然有效,在执行任何需要令牌的进一步操作之前,提供了一个额外的安全层。

2- 自行处理令牌

要生成认证令牌并自行处理,请调用以下方法

$authToken = TokensValidation::createNewAuthToken(
        userId: $uid,
        usingCookies: false
    );

    echo $authToken->getUserId();
    echo $authToken->getContent();

此方法为指定的用户 ID 生成新的认证令牌,并返回令牌对象而不会将其保存到任何位置,以便您按需处理。

要检查认证令牌,请调用以下方法并传递令牌作为参数

$result = TokensValidation::checkAuthToken(authToken: $authToken);
    if ($result->isValidationSucceed()) {
        // log in the user automatically,
        //for example :
        echo $result->getUserId();
        echo $result->getNewToken()->getContent();// save it in cookies or whatever you want
        autoLogin($result->getUserId());
    }
    else{
        //throw an error or redirect to log in
    }

3- 覆盖cookie处理器方法

要覆盖cookie处理器方法,创建一个继承自 AuthTokenCookiesHandler 类并实现 save()get()delete() 方法的类。然后,将 $AuthTokenCookiesHandler 属性设置为您的新的类名。以下是一个示例

use HichemtabTech\TokensValidation\Actions\Authentication\AuthTokenCookiesHandler;

class MyAuthTokenCookiesHandler extends AuthTokenCookiesHandler
{
    public function save(AuthToken $authToken): void
    {
        //save the $authToken in cookies or what ever you want
    }

    public function get(): ?string
    {
        //get it
    }

    public function delete(): void
    {
        //delete it
    }
}

TokensValidation::$AuthTokenCookiesHandler = MyAuthTokenCookiesHandler::class;

// this should be called after preparation

指纹

您可以通过使用浏览器指纹来为认证令牌添加额外的安全层。该库支持通过向 createNewAuthToken() 方法传递指纹字符串来实现指纹识别。

$authToken = TokensValidation::createNewAuthToken(
        userId: $uid,
        fingerPrint: $somefingerprint
    );

要使用指纹检查认证令牌,请使用带有指纹参数的 checkAuthToken() 方法。

$result = TokensValidation::checkAuthToken(authToken: $authToken, fingerPrint: $somefingerprint);

确认令牌

确认令牌是唯一代码,由 TokensValidation 生成,用于验证用户身份或确认他们对特定操作的授权。通常,确认令牌用于电子邮件验证或密码重置目的,尽管它们也可以用于其他目的。

确认过程可以分为两种类型:需要用户点击确认链接(通过URL)的确认过程和需要用户手动输入确认代码(通过键入)的确认过程。

1- 通过URL

在这种情况下,库生成一个包含加密用户 ID 的长令牌,并设计为包含在URL参数中。

$confirmationToken = TokensValidation::createNewConfirmationToken(
        userId: $uid,
        confirmationType: ConfirmationsTokenTypes::IN_URL
    );

    echo $confirmationToken->getContent();// if you want to view the long confirmation token
    echo $confirmationToken->getUrl("https:///email-check");// to get the full prepared url with the base url, https:///email-check

    //you will get the url like this:
    //https:///email-check?u=def5020080134ecc82ee1c1c2536ccdb0ec3c50161a9b6ab6f0f24c34730b73174327d2990ef8f583cec5f86ba7c3d44c5a5c0adae17313d09d5479fbe83c33e91f00d3902699507fc16266931be4e0f90382e4614aba6d8&c=nkyZDxMqbnS2oPs

您可以使用以下代码行来验证URL的内容。

$result = TokensValidation::checkConfirmationUrl(url: $url);
    if ($result->isValidationSucceed()) {
        //for example :
        echo $result->getUserId();
        //continue the request
    }
    else{
        //throw an error
    }

或者您可以直接注入 $_GET

$result = TokensValidation::checkConfirmationUrlParamsFromGET(_GET_ARRAY: $_GET);

要覆盖确认URL构建器方法,创建一个继承自 ConfirmationUrlBuilder 类并实现 getUrl(ConfirmationToken $confirmationToken, string $baseUrl)getUserIdAndTokenFromUrl(string $url)getUserIdAndTokenFromGET(array $_GET_ARRAY) 方法的类。然后,将 $ConfirmationUrlBuilder 属性设置为您的新的类名。以下是一个示例

use HichemtabTech\TokensValidation\Actions\Confirmation\ConfirmationUrlBuilder;
use HichemtabTech\TokensValidation\Actions\Confirmation\UserIdAndToken;
use HichemtabTech\TokensValidation\Model\Confirmation\ConfirmationToken;
use Purl\Url;

class MyConfirmationUrlBuilder extends ConfirmationUrlBuilder
{
    public function getUrl(ConfirmationToken $confirmationToken, string $baseUrl): string
    {
        $url = new Url($baseUrl);
        $url->query->set("uid", $confirmationToken->getUserId());// for userId
        $url->query->set("token", $confirmationToken->getContent());// for Code
        return $url->getUrl();
    }

    public function getUserIdAndTokenFromUrl(string $url): UserIdAndToken
    {
        $url = new Url($url);
        return UserIdAndToken::builder()
            ->setUserId($url->query->get("uid"))
            ->setToken($url->query->get("token"))
            ->build();
    }

    public function getUserIdAndTokenFromGET(array $_GET_ARRAY): UserIdAndToken
    {
        return UserIdAndToken::builder()
            ->setUserId($_GET_ARRAY["uid"]??"")
            ->setToken($_GET_ARRAY["token"]??"")
            ->build();
    }
}

TokensValidation::$ConfirmationUrlBuilder = MyConfirmationUrlBuilder::class;

// this should be called after preparation

2- 通过键入

在这种情况下,用户需要将库生成的确认令牌输入到表单字段中。库可以生成简短的确认令牌以提高便利性

$confirmationToken = TokensValidation::createNewConfirmationToken(
        userId: $uid,
        confirmationType: ConfirmationsTokenTypes::SMALL_CODE
    );

    echo $confirmationToken->getContent();


    $result = TokensValidation::checkConfirmationCode(code: $token);
    if ($result->isValidationSucceed()) {
        //for example :
        echo $result->getUserId();
        //continue the request
    }
    else{
        //throw an error
    }

WhatFor 字段

为了确保每个确认代码都用于其预期的目的,您可以在调用 createNewConfirmationToken 函数时包含一个 "whatFor" 参数。此参数允许您指定确认代码的目的,提供额外的安全性和准确性。

$confirmationToken = TokensValidation::createNewConfirmationToken(
        userId: $uid,
        confirmationType: ConfirmationsTokenTypes::SMALL_CODE,
        whatFor: "email-confirmation"
    );

要检查它

$result = TokensValidation::checkConfirmationCode(code: $token, whatFor: "email-confirmation");

如果“whatFor”参数与确认码的预期用途不匹配,验证过程将失败。

检查后删除

在某些情况下,你可能只想检查令牌并保持其活跃状态,例如(中间件检查)你只想检查令牌是否有效,然后稍后在另一个位置再进行检查。此参数允许你指定令牌在验证成功后是否将被删除。

$confirmationToken = TokensValidation::checkConfirmationCode(
        userId: $uid,
        confirmationType: ConfirmationsTokenTypes::SMALL_CODE,
        whatFor: "email-confirmation",
        deleteAfterCheck: false, //true by default
    );

每期一个令牌

为了避免在到期前同一时间创建多个确认码,你可以在调用 createNewConfirmationToken 函数时将“singleTokenPerTime”参数设置为true。此参数允许TokensValidation每次只创建一个确认码,如果用户请求具有相同目的(相同的whatFor值)的另一个代码,则库将仅返回具有不同到期日期的现有令牌。

$confirmationToken = TokensValidation::createNewConfirmationToken(
        userId: $uid,
        confirmationType: ConfirmationsTokenTypes::SMALL_CODE,
        whatFor: "email-confirmation",
        singleTokenPerTime: true
    );

令牌生成器

你可以通过创建一个扩展 AuthTokenGenerator::classConfirmationCodeGenerator::class 的新类来修改令牌和确认码生成器的行为。这允许你自定义生成器的功能以满足你项目的特定需求。

TokensValidation::$AuthTokenGenerator = MyAuthTokenGenerator::class;
TokensValidation::$ConfirmationCodeGenerator = MyConfirmationCodeGenerator::class;
TokensValidation::$InvitationTokenGenerator = MyInvitationTokenGenerator::class;

令牌过期

默认情况下,库生成的令牌在一段时间后过期(认证令牌为7天,确认令牌为10分钟)。你可以使用 setAuthTokenExpirationDelay()setConfirmationTokenExpirationDelay() 方法分别自定义这些过期周期。

// Set authentication token expiration period to 2 days
TokensValidation::setAuthTokenExpirationDelay(2 * 24 * 60 * 60);  // seconds

// Set confirmation token expiration period to 1 hour
TokensValidation::setConfirmationTokenExpirationDelay(60 * 60);  // seconds

//these lines should be called after preparation.

你可以通过将“expirationDelay”参数传递给生成确认令牌或认证令牌的函数来提供自定义的过期延迟。你可以通过以下代码实现

$confirmationToken = TokensValidation::createNewConfirmationToken(
        userId: $uid,
        expirationDelay: 60*60  // seconds
    );

邀请

库提供了一种创建带有令牌的邀请的功能,可以通过电子邮件发送给用户以授权他们执行某些操作,例如加入项目或成为管理员。为了使用此功能,在调用prepare()方法之前启用此功能是必要的。默认情况下,库包括两个启用的功能,即AuthToken和ConfirmationToken。要激活其他功能,应在调用 prepare() 之前调用此功能。

...
TokensValidation::setFeatures([
    'AuthTokens',
    'ConfirmationToken',
    'InvitationsTokens'
]);
...
TokensValidation::prepare();

或使用配置文件

<?php


return [
    ...

    'features' => [
        'AuthTokens',
        'ConfirmationToken',
        'InvitationsTokens'
    ]
    ...
];

创建邀请

你可以通过调用以下代码创建邀请

$invitation = TokensValidation::createInvitation(
        userId: $uid,
        target_email: "user@example.com",
        whatFor: "become-admin",
    );

echo $invitation->getUrl();

要调整库中邀请功能的默认参数,你需要修改配置设置或通过调用以下代码

TokensValidation::setInvitationTokenExpirationDelay(60*60*24);
TokensValidation::$InvitationBaseUrl = "https:///invitations";
TokensValidation::$InvitationTokenGenerator = MyInvitationTokenGenerator::class;
TokensValidation::$InvitationUrlBuilder = MyInvitationUrlBuilder::class;

检查邀请

通常,当使用邀请功能进行注册等操作时,用户需要提供一些信息。为了方便此过程,库允许检查邀请,使用户能够访问输入页面以提供所需信息。

<?php

$invitation = TokensValidation::checkInvitationToken(
    token: $_GET['token'],
    whatFor: "administration",
);

if (!$invitation->isValidationSucceed()) {
    redirectTo("/errors/invalid-invitation.html");
}

?>

<form method="post" action="">
    <input type="text" name="fname">
    <input type="text" name="lname">
    <input type="email" name="email" readonly value="<?php echo $invitation->getTargetEmail() ?>">
    <button>submit</button>
</form>

用户输入所需信息并提交表单后,需要再次检查令牌。一旦令牌被验证,就可以删除邀请或将其标记为“已接受”。以下是如何实现此操作的示例

...

//verify the data entered by the user.

...

$invitation = TokensValidation::checkInvitationToken(
    token: $_GET['token'],
    whatFor: "administration",
    thenAccept: true
);

if (!$invitation->isValidationSucceed()) {
    die("INVITATION_INVALID");
}

...

//insert the data entered by the user.
//performe some actions

echo "invitation accepted";

...

方法中的 thenAccept 参数用于在令牌检查和验证后标记邀请为“已接受”。这确保邀请不再活跃,将来无法再次使用。

在 Laravel 中

你可以使用名为config/tokensvalidation.php的配置文件来使用配置文件配置库及其参数。以下是tokensvalidation.php的示例

 // you can customize the Classes here
return [
    'connections' => [
        'mysql' => [
            'driver' => 'mysql',
            'host' => 'localhost',
            'database' => 'db',
            'username' => 'root',
            'password' => '',
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
        ],
    ],

    'AuthTokens' => [
        'expirationDelay' => 60*60*24*7,
        'AuthTokenGenerator' => MyAuthTokenGenerator::class,
        'AuthTokenCookiesHandler' => MyAuthTokenCookiesHandler::class,
    ],

    'ConfirmationToken' => [
        'expirationDelay' => 60*10,
        'ConfirmationUrlBuilder' => MyConfirmationUrlBuilder::class,
        'ConfirmationCodeGenerator' => MyConfirmationCodeGenerator::class,
        'UserIdEncrypter' => MyUserIdEncrypter::class
    ],

    'InvitationToken' => [
        'expirationDelay' => 60*60*24*3,
        'InvitationUrlBuilder' => InvitationUrlBuilder::class,
        'InvitationTokenGenerator' => InvitationTokenGenerator::class,
        'InvitationBaseUrl' => "https:///invitations",
    ],

    'features' => [
        'AuthTokens',
        'ConfirmationToken',
        //'InvitationsTokens'
    ]
];

要准备或发布你的文件到Laravel项目,你需要运行以下命令

php artisan vendor:publish --provider="HichemtabTech\TokensValidation\Laravel\Providers\TokensValidationProvider"

在Laravel项目中,你可以通过运行以下命令生成类以覆盖TokensValidation的默认类(ConfirmationUrlBuilder,AuthTokenCookiesHandler...)

php artisan tokens-validation:handler

然后,选择你想要生成的类,并遵循控制台中的说明。

错误识别

为了识别和解决可能发生的错误,您可以使用 $result->getCause() 函数,该函数返回一个参考代码以指示错误的特定原因。此函数可能返回几个可能的错误代码。

错误参考

许可

麻省理工学院