如果无法在函数中使用非确定性函数,那么在 SQL Server 中创建密码生成器用户定义函数的最佳方法是什么?
我想创建一个函数,该函数使用给定字符串中的字符返回随机生成的 varchar(10),例如:“1234567890QWERTYUIOPASDFGHJKLZXCVBNM”
我有自己的想法,但不是很自然的解决方案。
该功能背后的想法是,如果有人需要重置密码,我可以执行以下操作:
UPDATE Users SET Password = dbo.GeneratePassword() WHERE UserID = @UserID
一个函数比一个单独的预分配密码表更容易部署和重用。
您有几个选项(TL;DR -> 工作功能在选项 #2 的末尾,但另请参阅选项 #3 之后的更新部分!):
如果您只使用十六进制值(0 - 9 和 A - F),您可以调用SQL Server 2008 中引入的CRYPT_GEN_RANDOM :
返回:
如您所见,您需要使用函数
2
上的 format 选项,CONVERT
这样它就不会为您提供虽然更多样化但可能更难输入的字符,并且您不会获得领先的0x
. 但是你也可以看到,即使只有一行,多次调用也会得到不同的返回值(就像NEWID()
)。请注意传递给
CRYPT_GEN_RANDOM
函数的“长度”值。由于一个十六进制字节是 2 个字符,因此您只需要生成一个 5 字节的值。使用CONVERT(VARCHAR...
10 的“长度”,因为每个十六进制字节都变成一个字符。并且CONVERT(NVARCHAR...
使用 20 的“长度”,因为每 2 个字节将成为一个字符(在大多数情况下,在默认排序规则不以 结尾的数据库中运行它时)。_SC
您始终可以创建自己的算法并传入
CRYPT_GEN_RANDOM
随机方面的值。并且,如果您可以将您的算法构造为单一的SELECT
,以便可以在内联表值函数/iTVF(通常使用 CTE)中完成,那么您在技术上可以使用非确定性函数(至少有效),因为函数调用将传入表达式而不是该表达式的结果,就像它对多语句 TVF 和标量 UDF 所做的那样:然后运行测试:
只是为了确定 iTVF 中的多行:
返回:
将所有这些信息付诸实践,我们可以针对原始请求执行以下操作:
然后执行如下:
注意:请参阅下面的第 2 项与多行运行相关的内容!
您可以创建一个可以访问随机化功能的 SQLCLR 函数。这里的主要缺点是标量函数比 iTVF 更有可能缓存其返回值。
更新
鉴于问题更新中新提供的使用此功能的上下文:
我们可以解决在对此答案的评论中表达的以下问题:
真的。诚然,这有点不方便。但是,这并不否定这种方法解决手头问题的能力。它只需要一些关于如何正确使用此功能的评论/文档。
真的。但是没有必要在另一个函数中调用这个函数。这不需要是标量函数就可以在 中使用
UPDATE
:关于处理多行(请参阅上面选项 2 中的多行测试),任何类型的函数(至少是用户创建的)——标量 UDF、多语句 TVF、iTVF、SQLCLR UDF 或 SQLCLR TVF——都不是保证每行运行!您可能需要在如何说服查询优化器不缓存结果方面发挥创意,但可能会出现没有任何效果的情况。以下示例显示了相同的 iTVF 被调用两次。传入只会
@PasswordLength
导致输出值被缓存。但是,当您传入包含当前行中的字段的公式时,它的行为可能与您预期的一样:返回:
@BaconBits 在对该问题的评论中提出的观点是,最好不要存储可读密码,这是一个有效且好的观点。但是,情况可能会阻止该选项成为可能,或者至少在此时是可能的。
另一种选择是使用视图。
用法:
代码:
我用这个
但是因为 SQL-Server 太棒了,你不能在标量函数中使用 NEWID,所以我创建了一个额外的视图“dbo.random”。如下: