【发布时间】:2020-02-07 15:44:40
【问题描述】:
我在 SQL Server 中有一个表,用于保存用户的密码历史记录,以防止用户重复使用以前使用的密码。
CREATE TABLE user_password_histories
(
id BIGINT IDENTITY CONSTRAINT user_password_histories_pk PRIMARY KEY NONCLUSTERED
,password VARCHAR(128) NOT NULL
,user_id BIGINT NOT NULL
,created_at DATETIME DEFAULT GETUTCDATE() NOT NULL
,updated_at DATETIME
)
但是,我只想为用户维护一个包含 10 个密码历史记录的列表。因此,我正在考虑在插入期间使用触发器为每个用户保留 10 个历史记录。
我想出的部分解决方案是这样的
CREATE TRIGGER trg_user_password_histories
ON user_password_histories
AFTER INSERT
AS
DELETE FROM user_password_histories
WHERE user_password_histories.user_id = Inserted.user_id // This will not work
AND user_password_histories.id NOT IN (SELECT t2.id
FROM user_password_histories t2
WHERE t2.id = user_password_histories.id
ORDER BY t2.created_at DESC
OFFSET 10 ROWS)
GO
但这里的问题是Inserted 可以有多个条目。因此,我不确定如何解决此问题或解决此问题的最佳方法。
【问题讨论】:
-
老实说,我闻到了更大的问题;看起来您将纯文本密码存储在数据库中,而不是哈希和盐。我可能是错的,因为您很可能会重复使用
[User]表中的盐,而password是加盐的;但如果它被散列,我可以预期该列是nvarchar而不是varchar。在我看来,这是一个更大的问题,你应该首先解决这个问题。 -
只是想知道是什么让您认为我在这里使用纯密码只是通过查看数据库模式?我没有存储普通密码..它们都是加密的。
-
当您发布该评论时,我刚刚将我的推理添加到我的原始评论中。但是,就像我说的,它更像是一种“气味”。我可能错了,但是表格的 DDL 让它看起来确实有这个缺陷。
-
触发器永远不应该是第一选择;
INSERT触发DELETE似乎特别邪恶。除非您确实需要以某种方式为多个用户大量导入密码(?),否则为这个逻辑设置一个存储过程会更易于维护。 -
尽管我完全同意这看起来像纯文本密码并且触发器是错误的工作,因为失败的原因是因为在您的删除语句中您没有插入的表查询。您需要将 where 子句更改为连接,以便插入的表成为查询的一部分。如果是我,我会让这个删除逻辑非常不同。这将是我插入存储过程的一部分。
标签: sql sql-server database database-trigger