我正在尝试为我的REST API创建会话令牌。每次用户登录时,我都会通过
创建一个新令牌UUID token = UUID.randomUUID();
user.setSessionId(token.toString());
Sessions.INSTANCE.sessions.put(user.getName(), user.getSessionId());
但是,我不确定如何防止重复的sessionTokens。
例如:当user1登录并获得令牌87955dc9-d2ca-4f79-b7c8-b0223a32532a
并且用户2登录并且也获得令牌87955dc9-d2ca-4f79-b7c8-b0223a32532a
时,是否会出现这种情况。
有更好的方法吗?
答案 0 :(得分:39)
如果您遇到UUID冲突,请继续玩彩票。
来自维基百科:
随机生成的UUID有122个随机位。总共128个 比特,四个比特用于版本('随机生成的UUID'), 变量的两位('Leach-Salz')。
随机UUID, 可以使用计算两个具有相同值的机会 概率论(生日悖论)。使用近似值
p(n)\approx 1-e^{-\tfrac{n^2}{{2x}}}
这些是概率 计算n个UUID后出现意外冲突,x = 2122:
概率 68,719,476,736 = 236 0.0000000000000004(4×10-16) 2,199,023,255,552 = 241 0.0000000000004(4×10-13) 70,368,744,177,664 = 246 0.0000000004(4×10-10)将这些数字放入视角, 估计有人被陨石击中的年度风险 170亿的一次机会,这意味着概率大约是 0.00000000006(6×10-11),相当于创造几十万亿的几率> UUID在一年内有一个重复。在 换句话说,只有在每秒产生10亿UUID之后 在接下来的100年里,创造一个重复的概率 将是约50%。一次重复的概率大约是 如果地球上的每个人拥有6亿UUID,则为50%。
答案 1 :(得分:4)
Oracle UUID文档。 http://docs.oracle.com/javase/7/docs/api/java/util/UUID.html
他们使用来自互联网工程任务组的算法。 http://www.ietf.org/rfc/rfc4122.txt
摘要引用。
UUID长度为128位,可以保证唯一性 空间和时间。
虽然摘要声明了保证,但只有3.4 x 10^38
组合。 CodeChimp
答案 2 :(得分:2)
由于UUID的大小有限,因此无法在所有空间和时间内保持唯一。
如果您需要在任何合理用例中保证唯一的UUID,您可以使用Log4j 2的Uuid.getTimeBasedUuid()。只要您每毫秒产生的UUID少于10,000 UUID,它就保证在8,900年内是独一无二的。
答案 3 :(得分:0)
来自 UUID.randomUUID()
Javadoc:
用于检索类型 4(伪随机生成)UUID 的静态工厂。 UUID 是使用加密强的伪随机数生成器生成的。
这是随机的,因此肯定会发生碰撞,正如上面/下面的评论中确认的那样,很早就检测到了碰撞。 我建议您使用版本 1(基于时间)而不是版本 4(基于随机)。
可能的解决方案:
1) 来自 Log4j 的 UUID 实用程序
您可以使用 Log4j UuidUtil.getTimeBasedUuid()
中的第 3 方实现,该实现基于当前时间戳(从 1582 年 10 月 10 日起以 100 纳秒为单位测量),并与创建 UUID 的设备的 MAC 地址连接。请参阅工件 log4j-core 中的软件包 org.apache.logging.log4j.core.util
。
2) 来自 FasterXML 的 UUID 实用程序
还有来自 FasterXML Generators.timeBasedGenerator().generate()
的第 3 方实现,它也基于时间和 MAC 地址。请参阅工件 java-uuid-generator 中的软件包 com.fasterxml.uuid
。
3) 自己做
或者您可以使用核心 Java 的构造函数 new UUID(long mostSigBits, long leastSigBits)
实现您自己的。请参阅以下非常好的解释 Baeldung - Guide to UUID in Java,其中 1582 年 10 月 15 日(实际上是非常著名的一天)用于实施。