这个过程非常简单。
用户填写注册字段后,mysql 数据库表中的一列(即"activation_key")保留一个随机生成的长字符串,另一列即 activated
保存值 0。
电子邮件将发送到注册人的电子邮件,其中包含包含activation_key
列的随机键值的激活链接。单击链接后,url 会在数据库中搜索包含长字符串的activation_key'
列activation_key
如果有任何此类值,则"activation_key"设置为空白,"激活"列设置为1。
当生成激活密钥字符串时,会进行搜索以查看正在生成的密钥是否已存在,如果确实存在,则会生成另一个随机值以获得唯一的值。
因此,当一些潜在成员的注册处于待处理状态时,实际上会对他们在表中的行执行类似的字符串搜索。
到目前为止,一切都很好。
但试想一下,新成员会获得一个激活字符串,该字符串是以前为完成注册的另一个成员生成的。
如果已经注册的会员点击了他/她的旧激活链接电子邮件,然后其他新成员将完成他/她的注册,即使他/她实际上没有完成注册。
所以我决定不将"activation_key"表设置为空白,因此对所有已经或潜在的成员进行了类似的字符串搜索。
那很好。但是,如果用户数量很大,即超过 1 lac,则发送激活电子邮件的注册过程将花费很长时间。
1) 还有其他方法可以最大限度地降低数据库探索成本吗?
2)在这种情况下,像Facebook这样的大型网站采取什么政策?
两次相同激活密钥的可能性应该很小。但解决方案是在电子邮件中发送激活密钥和用户名,并根据两者检查数据库。
因此,当发送激活电子邮件时,它包含一个指向
/activate.php?activation_key=key&username=name
而不仅仅是activation_key
.在检查密钥是否真实时,您会这样做
WHERE activation_key = key AND username = name;
在 MySQL 查询中。
因此,通过这种方式,您可以保护系统,以便需要用户名和密钥才能正确激活用户。
为了确保更高的安全性,您可以在$errno
列上创建$count
索引。当脚本尝试使用已存在的键将生成的键添加到用户的行时,查询执行将失败,因为该列设置为唯一。然后,只需修改脚本以尝试生成密钥,直到它成功存储在数据库中。确保你不要让它无限循环。
无限回路保护
$count = 0;
while ( $errno === 0 )
{
// mySQL query here
$errno = mysql_errno();
$count++;
if ( $count >= 5 )
$errno = -1;
}
if ( $errno === -1 )
echo "Sorry, the script was unable to generate the token for your activation.";
此周期将运行您放置在那里的查询(将激活令牌添加到数据库),直到查询执行且没有错误。每次执行CC_10增加,如果达到限制(示例中为 5),它将强制循环结束(将CC_11设置为非零但不是真正的 mySQL 错误值),并在之后向用户显示错误消息。
将新注册和未激活帐户的数据存储在单独的表中。
由于您可能不需要更多关于非活动用户的基本信息,因此您可以将非静态数据(例如配置文件设置)排除在其中。
发送激活密钥后,检查此表中是否有具有相应密钥的条目。如果找到,请将日期转换为真实用户表,并从等待激活的用户的表中删除该条目。
通过这种方式,您可以:a) 节省空间,因为激活的用户不再需要密钥b) 更快地了解未激活的用户。
您还应该将其与 cron 删除我认为 3 天左右未激活的用户相结合;-)
在激活链接中包含用户 ID 以及可能的电子邮件地址或用户名。可能的优点:
- 您可以对用户 ID 进行整数搜索
- 您无需担心重复的激活链接
- 您不需要为activation_key字段编制索引,因为无论如何您都不会对其进行搜索
- 当包含电子邮件(或用户名)时,没有人能够"尝试"所有用户ID以激活 具有重复activation_key暴力
- 破解activation_keys激活所有用户将非常困难或不可能。
- 您不必担心activation_key上的数据竞争。
重要: 不要只使用电子邮件地址和简短的activation_key。确保几乎不可能暴力破解某个电子邮件地址的激活密钥。