asp.net 18 位 唯一 ID - 代码 可靠 性

tzdcorbm  于 2022-11-19  发布在  .NET
关注(0)|答案(9)|浏览(173)

我想要一个永远唯一的数字,我想出了下面的代码,它生成一个数字,并添加一个校验位到它的结尾,我想知道这个代码有多可靠?

public void GenerateUniqueNumber(out string ValidUniqueNumber) {
        string GeneratedUniqueNumber = "";

        // Default implementation of UNIX time of the current UTC time
        TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
        string FormatedDateTime = Convert.ToInt64(ts.TotalSeconds).ToString();
        string ssUniqueId = DateTime.UtcNow.ToString("fffffff");
        //Add Padding to UniqueId
        string FormatedUniqueId = ssUniqueId.PadLeft(7, '0'); 

        if (FormatedDateTime.Length == 10 && FormatedUniqueId.Length == 7)
        {
            // Calculate checksum number using Luhn's algorithm.
            int sum = 0;
            bool odd = true;
            string InputData = FormatedDateTime + FormatedUniqueId;
            int CheckSumNumber;

            for (int i = InputData.Length - 1; i >= 0; i--)
            {
                if (odd == true)
                {
                    int tSum = Convert.ToInt32(InputData[i].ToString()) * 2;
                    if (tSum >= 10)
                    {
                        string tData = tSum.ToString();
                        tSum = Convert.ToInt32(tData[0].ToString()) + Convert.ToInt32(tData[1].ToString());
                    }
                    sum += tSum;
                }
                else
                    sum += Convert.ToInt32(InputData[i].ToString());
                odd = !odd;
            }
            //CheckSumNumber = (((sum / 10) + 1) * 10) - sum;
            CheckSumNumber = (((sum + 9) / 10) * 10) - sum;

            // Compute Full length 18 digit UniqueNumber
            GeneratedUniqueNumber = FormatedDateTime + FormatedUniqueId + Convert.ToString(CheckSumNumber);
        }
        else
        {
            // Error
            GeneratedUniqueNumber = Convert.ToString(-1);
        }

        ValidUniqueNumber = GeneratedUniqueNumber;        
    }

**EDIT:**不能使用澄清GUID,需要通过电话键盘将号码输入IVR系统。

kupeojn6

kupeojn61#

您不能使用GUID,但是您可以创建类似GUID的own的唯一数字,它基于机器的MAC地址(空间)和当前时间和日期(时间)。如果所有机器都有同步的时钟,这就保证了唯一性。
有关详细信息,请参阅here

pxiryf3j

pxiryf3j2#

为什么不直接用Guid呢?

xj3cbfub

xj3cbfub3#

此方法有几个问题:

  • 基本上,您只是在计算从1970年1月1日起的毫秒数。您可以将ts.TotalSeconds舍入到0.0000001。所有的转换和毫秒计算都是不必要的。
  • 10年大约是3×10¹ ms,你保留了17位有效数字,所以在接下来的10年里,前5位数字永远不会改变,也不能用来区分数字,它们毫无用处。
  • 您是否生成了1970年到现在之间的毫秒数?如果没有,它们也不能用来区分数字,毫无用处。
  • 这完全取决于哪台机器返回日期。任何可以访问这台机器的人都可以生成他们想要的任何“唯一”数字。这是问题吗?
  • 任何看到这些数字的人都可以知道它是什么时候生成的。这有问题吗?
  • 任何人都可以预测什么时候会产生什么数字,这有问题吗?
  • 1015毫秒大约是30000年,之后,你的算法会重复数字,看起来很长,但你指定了“永远”,30000年不是“永远”,你真的是指“永远”吗?
57hvy0tb

57hvy0tb4#

如果我对您的实现理解正确的话,它只使用当前日期/时间作为基础。这意味着如果您同时创建两个ID,它们将不是唯一的。

klh5stk1

klh5stk15#

由于您提到(在注解中)ID存储在DB中,因此您可以使用您提到的方法或随机生成ID,并检查DB中是否存在ID。
如果它已经存在,则生成一个新的,否则就完成了。
但是有一点,我会确保在事务中检查ID的存在性并将记录实际保存到DB,否则您将面临在检查ID和创建行之间有另一个请求创建该记录的风险。
同样只是检查一下,为什么数据库本身生成的自动递增数字不起作用呢?DB会保证它的唯一性(无论如何,对于那个表)

qmelpv7a

qmelpv7a6#

你没有说这些号码是用来做什么的,它们是否有某种价值与之相关?如果用户能搞清楚方案,猜出有效的票号,会不会有问题?
如果重要的是这些数字很难猜测,这个方案福尔斯了;你可以用一个单调递增的序列号并用一个分组密码(64位的分组大小)加密它;这将提供一个64位的输出或大约20位十进制数字,您可以取(比如)的最后18位。(如果可逆性很重要,即给定一个票证编号,您希望能够恢复序列号,则需要在此处更加小心。)
你是否需要一个100%的保证,保证所有的票号都不会是相同的?如果是这样,你需要把它们保存在一个数据库中,并在使用它们时将它们标记出来。如果你这样做了,那么使用一个好的随机数生成器并每次检查是否有重复的票号可能是合理的。

inn6fuwd

inn6fuwd7#

使用系统时间是一个很好的开始,但是如果需要同时生成两个UID,就会产生冲突。使用“fffffff”格式也没有帮助:Windows的时钟分辨率只有15-16毫秒,所以那些“f“中只有一两个有什么好处。
此外,您的方法会告诉您ID是何时产生的。根据您的需求,这可能是您想要的功能,也可能是安全性风险。
除了时间之外,您还需要在ID中包含其他信息。一些可能的选择包括:

  • 随机数
  • 循环计数器
  • 程序名称的哈希值(如果在多个程序中需要这些ID)
  • 机器的MAC位址或其他识别码(如果识别码在多部计算机中必须是唯一的)

如果你想 * 确保 * 唯一性,那么把你的ID存储在一个数据库中,这样你就可以检查重复。

wgeznvg7

wgeznvg78#

正如“Andrew Hare”所说,你可以使用Guid。关于你的代码,答案是“NO”!因为如果客户端计算机的日期时间是错误的,或者更改结果可能是两个或更多!

3wabscal

3wabscal9#

反正没有随机这回事。我有个建议。
1.创建您自己的“随机”18位数字
1.在将其发送给用户之前,请根据DB中的现有数据进行检查
1.如果已经在DB中,冲洗并重复。

相关问题