设计困境:如果已经使用了电子邮件地址,请发送电子邮件"已经注册的电子邮件地址",但不能,因为无法将重复添加到表中

时间:2013-08-09 19:14:04

标签: mysql security language-agnostic registration confirmation-email

注册表单要求用户名电子邮件地址。数据通过验证后,它会添加到accounts表中。它存储用户名,密码和电子邮件地址等数据。如果已经使用了用户名,则将通知用户,并且不会向表中添加任何数据。如果立即通知用户该电子邮件地址已在表中,则将其视为security issue。建议的解决方案是始终发送验证电子邮件,如果输入的用户名已经存在,则电子邮件会显示“此电子邮件地址已被使用”(并且没有激活链接)当然会给出。)

问题是因为它现在有效,如果INSERT查询无法将数据插入表中,则会显示消息“Username taken”。这可能是错误的,因为表中的电子邮件地址设置为唯一,因此如果输入相同的电子邮件地址,查询将失败。我不能再发送验证电子邮件说“此电子邮件地址已被使用”,因为包含所述电子邮件地址的表中没有记录。

如何重新设计系统以使其有效?

我正在使用MySQL而且表accounts具有主键username唯一键e-mail以及属性passwordactivation

if(mysqli_stmt_execute($createAccount))
    echo 'Username available!';
else
    echo 'Username unavailable!';

在SQL中是否有某种方法可以检查查询无法插入表中的原因?例如,它可以告诉哪个属性有重复值吗?

如果我的问题不清楚,请告诉我。

2 个答案:

答案 0 :(得分:1)

首先运行SELECT查询以识别重复项。如果未找到重复项,则可以执行INSERT。

答案 1 :(得分:0)

如果您希望数据库在插入数据时执行所需的检查,您希望能够区分失败的尝试要添加电子邮件和尝试添加用户名失败,最直接的解决方案是同时拥有email表和username表。您的实际account表只会保留这两个表的外键。以下是http://sqlfiddle.com/#!2/a24df示例:

CREATE TABLE username (id INT AUTO_INCREMENT PRIMARY KEY NOT NULL, value CHAR(80) UNIQUE NOT NULL);
CREATE TABLE email (id  INT AUTO_INCREMENT PRIMARY KEY NOT NULL, value CHAR(80) UNIQUE NOT NULL);

CREATE TABLE account(id  INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
                     username_id  INT NOT NULL,
                     email_id INT NOT NULL,
                     FOREIGN KEY (username_id) REFERENCES username(id),
                     FOREIGN KEY (email_id) REFERENCES email(id) );

添加新用户现在将作为事务中的几个步骤执行。您现在可以知道哪一步失败了。并且在交易中,这将保留帐户创建的原子性:

START TRANSACTION;
INSERT INTO email(value) VALUES ("x@y.com");
INSERT INTO username(value) VALUES ("Sylvain");

-- you could obtain the ID programmatically by "last_insert_id"-like function 
INSERT INTO account(username_id, email_id) VALUES (1,1); 
COMMIT;

查询给定帐户的用户名和电子邮件现在需要加入:

SELECT username.value AS username, email.value AS email 
FROM username JOIN account ON username.id = account.username_id
JOIN email ON email.id = account.email_id
WHERE account.id = 1;

我不会说这是最好的解决方案,但我认为它可以按你的意愿运作。