生成一次性使用URL

A one-time URL is a specially crafted address that is valid for one use only. It’s usually provided to a user to gain privileged access to a file for a limited time or as part of a particular activity, such as user account validation. In this article I’ll show how to generate, implement, and expire one-time URLs.

一次性URL是特制的地址,仅可一次使用。 通常提供给用户以在有限的时间内或在特定活动(例如用户帐户验证)的一部分中获得对文件的特权访问。 在本文中,我将展示如何生成,实现和终止一次性URL。

创建一个URL (Creating a URL)

Let’s say we’ve been tasked with writing a user management component, and the project creates a record for a new user account in the database. After signing up, the user receives a confirmation email which provides a one-time URL to activate her account. We can make this URL one-time by including a tracked token parameter, which means the URL would look like this:

假设我们的任务是编写一个用户管理组件,并且该项目为数据库中的新用户帐户创建了一条记录。 注册后,用户会收到一封确认电子邮件,其中提供了一个一次性URL来激活她的帐户。 我们可以通过包含一个跟踪的令牌参数来一次性创建此URL,这意味着该URL如下所示:

http://example.com/activate?token=ee97780...

Not surprisingly, tracking the one-time URL is done by storing information in a database table. So, let’s start with the table definition:

毫不奇怪,通过将信息存储在数据库表中来跟踪一次性URL。 因此,让我们从表定义开始:

CREATE TABLE pending_users (
    token CHAR(40) NOT NULL,
    username VARCHAR(45) NOT NULL,
    tstamp INTEGER UNSIGNED NOT NULL,
    PRIMARY KEY(token)
);

The table stores the relevant username, a unique token, and a timestamp. I’ll be showing how to generate the token using the sha1() function, which returns a 40-character string, hence the capacity of the token field as 40. The tstamp field is an unsigned integer field used to store a timestamp indicating when the token was generated and can be used if we want to implement a mechanism by which the token expires after a certain amount of time.

该表存储了相关的用户名,唯一令牌和时间戳。 我将展示如何使用sha1()函数生成令牌,该函数返回一个40个字符的字符串,因此令牌字段的容量为tstamp字段是一个无符号整数字段,用于存储时间戳,指示何时如果我们想实现一种机制,令牌可以在一定时间后过期,那么令牌就可以生成并可以使用。

There are many ways to generate a token, but here I’ll simply use the uniqid() and sha1() functions. Regardless of how you choose to generate your tokens, you’ll want them to be unpredictable (random) and a low chance of duplication (collision).

生成令牌的方法有很多,但是在这里我将仅使用uniqid()sha1()函数。 无论选择哪种方式生成令牌,都希望它们是不可预测的(随机),并且复制的可能性很小(冲突)。

<?php
$token = sha1(uniqid($username, true));

uniqid() accepts a string and returns a unique identifier based on the string and the current time in microseconds. The function also accepts an optional Boolean argument to add additional entropy to make the result more unique. The sha1() function calculates the hash of the given string using the US Secure Hash Algorithm 1.

uniqid()接受字符串,并根据字符串和当前时间(以微秒为单位uniqid()返回唯一标识符。 该函数还接受一个可选的布尔参数,以添加附加的熵以使结果更加唯一。 sha1()函数使用美国安全哈希算法1计算给定字符串的哈希。

Once the functions execute, we’ve got a unique 40-character string which we can use as our token to create the one-time URL. We’ll want to record the token along with the username and timestamp in the database so we can reference it later.

函数执行后,我们将获得一个唯一的40个字符的字符串,可以将其用作令牌来创建一次性URL。 我们希望将令牌以及用户名和时间戳记录在数据库中,以便稍后使用。

<?php
$query = $db->prepare(
    "INSERT INTO pending_users (username, token, tstamp) VALUES (?, ?, ?)"
);
$query->execute(
    array(
        $username,
        $token,
        $_SERVER["REQUEST_TIME"]
    )
);

Obviously we want to store the token, but we also store the username to remember which user to set active, and a timestamp. In a real world application you’d probably store the user ID and reference a user record in a separate user table, but I’m using the username string for example’s sake.

显然,我们要存储令牌,但是我们还要存储用户名,以记住将哪个用户设置为活动状态以及时间戳。 在现实世界的应用程序中,您可能会存储用户ID并在单独的用户表中引用用户记录,但是例如,我使用用户名字符串。

With the information safely placed in the database, we can now construct our one-time URL which points to a script that receives the token and processes it accordingly.

将信息安全地放置在数据库中之后,我们现在可以构建一次性URL,该URL指向接收令牌并进行相应处理的脚本。

<?php
$url = "http://example.com/activate.php?token=$token";

The URL can be disseminated to the user either by email or some other means.

可以通过电子邮件或其他方式将URL分发给用户。

<?php
$message = <<<ENDMSG
Thank you for signing up at our site.  Please go to
$url to activate your account.
ENDMSG;

mail($address, "Activate your account", $message);

消耗URL (Consuming a URL)

We need a script to activate the account once the user follows the link. Indeed, it’s the processing script that works that enforces the one-time use of the URL. What this means is the script will need to glean the token from the calling URL and do a quick check against the data stored in the database table. If it’s a valid token, we can perform whatever action we want, in this case setting the user active and expiring the token.

一旦用户点击链接,我们需要一个脚本来激活帐户。 确实,强制执行URL的一次性使用的是处理脚本。 这意味着脚本将需要从调用URL中收集令牌,并对存储在数据库表中的数据进行快速检查。 如果它是有效的令牌,我们可以执行所需的任何操作,在这种情况下,将用户设置为活动状态并使令牌过期。

<?php
// retrieve token
if (isset($_GET["token"]) && preg_match('/^[0-9A-F]{40}$/i', $_GET["token"])) {
    $token = $_GET["token"];
}
else {
    throw new Exception("Valid token not provided.");
}

// verify token
$query = $db->prepare("SELECT username, tstamp FROM pending_users WHERE token = ?");
$query->execute(array($token));
$row = $query->fetch(PDO::FETCH_ASSOC);
$query->closeCursor();

if ($row) {
    extract($row);
}
else {
    throw new Exception("Valid token not provided.");
}

// do one-time action here, like activating a user account
// ...

// delete token so it can't be used again
$query = $db->prepare(
    "DELETE FROM pending_users WHERE username = ? AND token = ? AND tstamp = ?",
);
$query->execute(
    array(
        $username,
        $token,
        $tstamp
    )
);

Going further, we could enforce a 24-hour TTL (time to live) for the URL buy checking the timestamp stored in the table alongside the token.

更进一步,我们可以对URL购买强制执行24小时TTL(生存时间),以检查令牌旁边存储在表中的时间戳。

<?php
// 1 day measured in seconds = 60 seconds * 60 minutes * 24 hours
$delta = 86400;

// Check to see if link has expired
if ($_SERVER["REQUEST_TIME"] - $tstamp > $delta) {
    throw new Exception("Token has expired.");
}
// do one-time action here, like activating a user account
// ...

Working within the realm of Unix timestamps, the expiration date would be expressed as an offset in seconds. If the URL is only supposed to be valid for 24 hours, we have a window of 86,400 seconds. Determining if the link has expired then becomes a simple matter of comparing the current time with the original timestamp and see if the difference between them is less than the expiration delta. If the difference is greater than the delta, then the link should be expired. If the difference is less than or equal to the delta, the link is still “fresh.”

在Unix时间戳范围内工作,到期日期将表示为以秒为单位的偏移量。 如果该URL仅应在24小时内有效,则我们的窗口为86,400秒。 比较当前时间和原始时间戳,并确定它们之间的差值是否小于到期时间增量,即可确定链接是否已过期。 如果差异大于增量,则链接应过期。 如果差异小于或等于增量,则链接仍然“新鲜”。

结论 (Conclusion)

There are several applications for one-time use URLs. The example in this article was a scenario of sending a user a verification link to activate an account. You could also use one-time use URLs to provide confirmation for other activities, give time-sensitive access to information, or to create timed user accounts which expire after a certain time.

一次性使用URL有几种应用程序。 本文中的示例是向用户发送验证链接以激活帐户的场景。 您也可以使用一次性使用URL来确认其他活动,提供对时间敏感的信息访问权限或创建定时的用户帐户,这些帐户在特定时间后到期。

As a matter of general house keeping you could write a secondary script to keep expired tokens from accumulating in the database if a user never follows them. The script could be run periodically by an administrator, or preferably set up as a scheduled task or cron job and run automatically.

一般而言,如果用户从不关注过期的令牌,则可以编写辅助脚本来防止过期的令牌在数据库中累积。 该脚本可以由管理员定期运行,或者最好设置为计划任务或cron作业并自动运行。

It would also be wise to take this functionality and wrap it up into a reusable component as you implemented it in your application. It’s trivial to do, and so I’ll leave that as an exercise to the reader.

在您在应用程序中实现该功能并将其包装成可重用的组件时,也是明智的。 这样做很简单,因此我将其留给读者练习。

Image via Fotolia

图片来自Fotolia

翻译自: https://www.sitepoint.com/generating-one-time-use-urls/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值