c# - 使用 DateTime Tick 计数生成 Nonce
问题描述
在我们的 Web 应用程序中,我们为某个功能使用外部服务。要请求该外部服务,我们必须添加一个key
请求标头,它是一个整数,并且对我的所有请求都是唯一的,技术上调用nonce
对于我使用的随机数生成
var nonce = (long) DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).Ticks*100 + random.Next(100);
现在,在 100 个并发请求中,密钥被复制。密钥是如何复制的?
我不能使用 GUID,因为我需要不断增加整数值。
解决方案
如果您有真正的并发请求,那么DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).Ticks * 100
对于这些请求来说是一个常量。然后你就只剩下了random.Next(100)
,那么碰撞并不需要太多。一个微不足道(但不理想)的选择就是简单地做random.Next()
.
一个更好的主意是:
[ThreadStatic]
private static Random __random = new Random();
private static int shift = 32;
private static long counter = 0L;
public long GenerateNextNonce()
{
var major = ++counter << shift;
var minor = (DateTime.UtcNow.Ticks ^ __random.Next()) & (1L << shift - 1);
return major + minor;
}
这++counter
可确保您拥有越来越多的数字序列 - 仅此一项就足以产生随机数,但它是高度可预测的,因此很容易被黑客攻击。
计算DateTime.UtcNow.Ticks ^ __random.Next()
确保了一个不完全依赖于实现的相当随机的数字,Random
因此它确保了这个数字是高度不可预测的,但它不一定会增加。
该shift
值的使用可确保将counter
值转移到数字的“高端”或主要部分。调用(DateTime.UtcNow.Ticks ^ __random.Next()) & (1L << shift - 1)
会截断随机数随机部分的高端位,确保次要值不与主要编号共享任何位。
我用一个shift
值32
和产生的100_000_000
值来运行它,并且只用尽了不到 5% 的可用数字long.MaxValue
。只要你生产的随机数少于 20 亿,你就应该是好的。如果你想要更多然后减少shift
。
推荐阅读
- mysql - 无法在 mysql workbench 6.3 (Linux mint 18.3) 中选择表/模式
- ruby-on-rails - 在 Rails 中调用 Postgres 存储函数的最佳方法是什么?
- heroku - 将 Angular7 项目部署到 Heroku 问题
- blogs - 更新 _config.yml 后,Hexo 博客标题不会改变
- types - 在 Julia 中通过 TCP 读取复合类型
- php - 如何通过在 php 中抓取来搜索社交媒体网站上的用户名
- css - 在 Angular 8 中根据所选主题(在 ui 中选择)更改 css 类的属性
- c# - 已发布的 Windows 应用程序中发生有关无法加载文件或程序集“Microsoft.SqlServer.BatchParser”的异常
- mongodb - mongo:加载共享库时出错:libcrypto.so.1.1:无法打开共享对象文件:没有这样的文件或目录
- django - 带有来自不同模型的键的外键列