【问题标题】:Generate unique identification tokens and store them生成唯一标识令牌并存储它们
【发布时间】:2021-04-21 09:36:17
【问题描述】:

对于我的应用程序,我必须生成独特的 tonken。用户将能够通过 URL“https:xxxx.com/TOKEN”访问与他有关的文档。

令牌将由字母“2346789abcdefghjkmnpqrtuvwxyz”中的 6 个字符组成。

随机生成这些令牌的最佳方法是什么? (我正在开发一个带有 SQL 数据库的 .NET MVC 中的 Web 应用程序)。

我想到了一个 SQL 存储过程,它生成一个介于 1 和 594823321 之间的随机数,然后将其转换为我的自定义基数 29。

但是如何生成一个未使用的随机数呢?

提前感谢您的帮助。

【问题讨论】:

  • 它们需要随机吗?
  • 如果要求它们是唯一的,则不能随机生成它们。想象一下您有 N 个可用号码并使用了 N-1 个号码的情况。最后一个可用的数字是固定的,而不是随机的。
  • 这可能会为您提供一些提示和想法:stackoverflow.com/questions/1458468/youtube-like-guid。为了确保唯一性,然后将其作为主键存储在数据库中,或者在 C# 中使用 HashSet
  • 尝试以下操作:随机 rand = new Random();字符串输入=“2346789abcdefghjkmnpqrtuvwxyz”;字符串输出 = string.Join("", input.ToCharArray().OrderBy(x => rand.Next()).Take(6));这会产生一个没有重复的字符串。
  • 您可以使用 SQL 自动增量来生成数字的线性级数,然后使用某种重新排序位的方法来生成一个看似随机但永远不会重复的数字。 (可能会希望从高于零开始自动递增的数字)

标签: c# sql security authentication math


【解决方案1】:

大多数人使用Guid.NewGuid().ToString(); 在此处阅读更多信息:Microsoft Docs

GUID 是一个 128 位整数(16 个字节),可在需要唯一标识符的所有计算机和网络中使用。这样的标识符被复制的概率非常低。

【讨论】:

    【解决方案2】:

    返回不重叠的 6 个字符的值非常棘手。正如 Costa 所提到的,规范的解决方案是使用 UUID。几乎可以保证是独一无二的。但它们不是 6 个字符。

    如果它们不需要“随机”,您可以生成一个数字并将其转换为您想要的格式:

    select concat(substring(c.chars, (v.n / power(len(c.chars), 5)) % len(c.chars) + 1, 1),
                  substring(c.chars, (v.n / power(len(c.chars), 4)) % len(c.chars) + 1, 1),
                  substring(c.chars, (v.n / power(len(c.chars), 3)) % len(c.chars) + 1, 1),
                  substring(c.chars, (v.n / power(len(c.chars), 2)) % len(c.chars) + 1, 1),
                  substring(c.chars, (v.n / power(len(c.chars), 1)) % len(c.chars) + 1, 1),
                  substring(c.chars, (v.n / power(len(c.chars), 0)) % len(c.chars) + 1, 1)
                 )
    from (values (0), (1), (100), (1000), (10000), (100000), (1000000), (10000000), (100000000)) v(n) cross join
         (values ('2346789abcdefghjkmnpqrtuvwxyz')) c(chars);
    

    Here 是一个 dbfiddle。对于n 值,您可以使用序列,或者如果您每秒不需要超过一个值,则可以使用自某个截止值以来的秒数。

    请注意,您可以“调整”上述内容以使其看起来更加随机。例如,您可以将v.n 乘以某个大随机数:

    select concat(substring(c.chars, (v.n * 1000117 / power(len(c.chars), 5)) % len(c.chars) + 1, 1),
                  substring(c.chars, (v.n * 1000117 / power(len(c.chars), 4)) % len(c.chars) + 1, 1),
                  substring(c.chars, (v.n * 1000117 / power(len(c.chars), 3)) % len(c.chars) + 1, 1),
                  substring(c.chars, (v.n * 1000117 / power(len(c.chars), 2)) % len(c.chars) + 1, 1),
                  substring(c.chars, (v.n * 1000117 / power(len(c.chars), 1)) % len(c.chars) + 1, 1),
                  substring(c.chars, (v.n * 1000117 / power(len(c.chars), 0)) % len(c.chars) + 1, 1)
                 )
    from (values (cast(0 as bigint)), (1), (100), (1000), (10000), (100000), (1000000), (10000000), (100000000)) v(n) cross join
         (values ('2346789abcdefghjkmnpqrtuvwxyz')) c(chars);
    

    这对于您想要做的事情可能已经足够了。

    如果没有这一点,蛮力是一种选择。只有 594,823,321 个不同的值。这很容易放入桌子。因此,您可以生成它们,然后使用该表来确保不会重复。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-24
      • 1970-01-01
      • 2017-12-06
      • 1970-01-01
      相关资源
      最近更新 更多