18位数唯一ID - 代码可靠性

时间:2010-06-26 14:19:50

标签: c# asp.net uniqueidentifier

我想要一个永远独一无二的数字,我想出了以下代码, 它生成一个数字并在其末尾添加一个校验位,我想知道这段代码有多可靠?

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;        
    }

编辑:澄清 无法使用GUID,需要通过电话键盘将数字输入IVR系统。

9 个答案:

答案 0 :(得分:6)

您不能使用GUID,但您可以创建与GUID类似的唯一编号的own格式,该格式基于机器的MAC地址(空格)以及当前时间和日期(时间)。如果机器都具有同步时钟,则保证这是唯一的。

有关详细信息,请参阅here

答案 1 :(得分:5)

为什么不使用Guid

答案 2 :(得分:4)

此方法存在一些问题:

  • 你基本上只计算从1970年1月1日开始的毫秒数。你可以从ts.TotalSeconds四舍五入到0.0000001。您的所有转换和毫秒计算都是不必要的。

  • 10年约为3×10 11毫秒。您保留了17位有效数字,因此在接下来的10年中,前5位数字将永远不会改变,也不能用于区分数字。它们毫无用处。

  • 您是否在1970年至今之间生成毫秒数?如果没有,它们也不能用来区分数字而且没用。

  • 这完全取决于什么机器返回日期。有权访问此计算机的任何人都可以生成他们想要的任何“唯一”数字。这是问题吗?

  • 任何看到其中一个号码的人都可以知道它何时生成。这是一个问题吗?

  • 任何人都可以预测何时生成的数字。这是一个问题吗?

  • 10 15 毫秒大约是30000年。之后,您的算法将重复数字。似乎很长一段时间,但你指定“永远”,而30000年不是“永远”。你的意思是“永远”吗?

答案 3 :(得分:3)

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

答案 4 :(得分:1)

由于您(在评论中)提到ID存储在数据库中,您可以使用您提到的方法或随机生成ID,并检查数据库中是否存在。

如果它已经存在,请生成一个新的,否则你就完成了。

但有一点,我会确保在事务中检查是否存在ID以及将记录实际保存到数据库中,否则您将面临另一个请求创建该记录的风险。检查ID和行的创建。

同样只是检查,为什么数据库本身生成的自动增量号不起作用?数据库将保证它的唯一性(无论如何,对于该表)

答案 5 :(得分:1)

您没有说明这些数字的用途。他们是否有某种与他们相关的价值?如果用户能够找出方案并猜出有效的票号,会不会有问题?

如果难以猜测这些数字很重要,那么这个方案就会失败;输出看起来非常随机的数据的东西会更好。您可以采用单调递增的序列号并使用块密码(具有64位块大小)对其进行加密;这给你一个64位输出或大约20个十进制数字值,你可以采取(比如说)最后18位。 (如果可逆性很重要,即给定一个票号以便你能够恢复序列号,你需要在这里更加小心。)

您是否需要铸铁100%保证没有门票号码相同?如果是这样,您需要将它们保存在数据库中并在使用时将其标记为关闭。如果你这样做,那么每次使用一个好的随机数发生器并检查欺骗可能是合理的。

答案 6 :(得分:1)

使用系统时间是一个很好的开始,但如果您需要同时生成两个UID,它会给您带来冲突。你使用“fffffff”格式没有任何帮助:Windows时钟分辨率只有15-16毫秒,所以只有一两个“f”在做任何好事。

此外,您的方法会告诉您何时生成ID。根据您的需要,这可能是一个理想的功能,或者可能存在安全风险。

除了时间之外,您还需要使用您的ID来包含其他信息。一些可能的选择是:

  • 随机数
  • 循环计数器
  • 程序名称的哈希值(如果您需要在多个程序中使用这些ID)
  • 计算机的MAC地址或其他标识符(如果ID需要在多台计算机上唯一)

如果您想确保唯一性,请将您的ID存储在数据库中,以便检查重复项。

答案 7 :(得分:0)

正如“Andrew Hare”所说,你可以使用Guid。 关于你的代码答案是“不”! 因为如果客户的计算机的DateTime错误或更改结果可能是几个或更多!

答案 8 :(得分:-1)

无论如何都没有随机的东西。这是一个建议。

  1. 创建您自己的“随机”18位数字
  2. 在将其发送给用户之前,请根据DB
  3. 中的现有内容进行检查
  4. 如果已经在DB中,请冲洗并重复。