C# 双因素Google身份验证与服务器上的代码不匹配-ASP.Net MVC

C# 双因素Google身份验证与服务器上的代码不匹配-ASP.Net MVC,c#,validation,two-factor-authentication,google-authenticator,C#,Validation,Two Factor Authentication,Google Authenticator,我在使用google authenticator的双因素身份验证中使用以下代码。 这个验证的问题是,google authenticator代码在我的本地机器上正确验证,但在服务器上没有。 服务器时间设置为:(UTC-05:00)东部时间(美国和加拿大) 我的系统时间设置为:(UTC-06:00)中央时间(美国和加拿大) 在服务器上,当我多次尝试点击“验证”按钮时,它有时会正确验证,有时则不会。我不知道它为什么这样做 任何人都可以帮我提出解决这个问题的想法/建议 public static c

我在使用google authenticator的双因素身份验证中使用以下代码。 这个验证的问题是,google authenticator代码在我的本地机器上正确验证,但在服务器上没有。 服务器时间设置为:(UTC-05:00)东部时间(美国和加拿大) 我的系统时间设置为:(UTC-06:00)中央时间(美国和加拿大)

在服务器上,当我多次尝试点击“验证”按钮时,它有时会正确验证,有时则不会。我不知道它为什么这样做

任何人都可以帮我提出解决这个问题的想法/建议

 public static class TimeBasedOneTimePassword
    {
        public static readonly DateTime UNIX_EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        private static MemoryCache _cache;

        static TimeBasedOneTimePassword()
        {
          _cache = new MemoryCache("TimeBasedOneTimePassword");
        }

        public static string GetPassword(string secret)
        {
          return GetPassword(secret, GetCurrentCounter());
        }

        public static string GetPassword(string secret, DateTime epoch, int timeStep)
        {
          long counter = GetCurrentCounter(DateTime.UtcNow, epoch, timeStep);
          return GetPassword(secret, counter);
        }

        public static string GetPassword(string secret, DateTime now, DateTime epoch, int timeStep, int digits)
        {
          long counter = GetCurrentCounter(now, epoch, timeStep);
          return GetPassword(secret, counter, digits);
        }

        private static string GetPassword(string secret, long counter, int digits = 6)
        {
          return HashedOneTimePassword.GeneratePassword(secret, counter, digits);
        }

        private static long GetCurrentCounter()
        {
          return GetCurrentCounter(DateTime.UtcNow, UNIX_EPOCH, 30);
        }

        public static long GetCurrentRemaining()
        {
          return (long)(DateTime.UtcNow - UNIX_EPOCH).TotalSeconds % 30;
        }


        private static long GetCurrentCounter(DateTime now, DateTime epoch, int timeStep)
        {
          return (long)(now - epoch).TotalSeconds / timeStep;
        }

        public static bool IsValid(string secret, string password, int checkAdjacentIntervals = 1)
        {
          if (password == GetPassword(secret))
            return true;

          for (int i = 1; i <= checkAdjacentIntervals; i++)
          {
             if (password == GetPassword(secret, GetCurrentCounter() + i))
                return true;

             if (password == GetPassword(secret, GetCurrentCounter() - i))
                return true;
          }

          return false;
        }
    }
public静态类TimeBasedOneTimePassword
{
public static readonly DateTime UNIX_EPOCH=new DateTime(1970,1,1,0,0,DateTimeKind.Utc);
私有静态内存缓存;
静态TimeBasedOneTimePassword()
{
_缓存=新的MemoryCache(“TimeBasedOneTimePassword”);
}
公共静态字符串GetPassword(字符串机密)
{
返回GetPassword(secret,GetCurrentCounter());
}
公共静态字符串GetPassword(字符串机密、日期时间历元、int-timeStep)
{
长计数器=GetCurrentCounter(DateTime.UtcNow、epoch、timeStep);
返回GetPassword(密码、计数器);
}
公共静态字符串GetPassword(字符串机密、日期时间、日期时间历元、整数时间步长、整数位数)
{
长计数器=GetCurrentCounter(现在、历元、时间步);
返回GetPassword(密码、计数器、数字);
}
私有静态字符串GetPassword(字符串机密、长计数器、整数位数=6)
{
返回HashedOnItemPassword.GeneratePassword(密码、计数器、数字);
}
私有静态长GetCurrentCounter()
{
返回GetCurrentCounter(DateTime.UtcNow,UNIX\u EPOCH,30);
}
公共静态long GetCurrentRestain()
{
返回(长)(DateTime.UtcNow-UNIX_EPOCH)。总秒数%30;
}
私有静态长GetCurrentCounter(现在日期时间、日期时间历元、整数时间步)
{
返回(长)(现在-历元).TotalSeconds/timeStep;
}
公共静态bool有效(字符串机密、字符串密码、int-checkAdjacenterVals=1)
{
if(password==GetPassword(secret))
返回true;

对于(int i=1;i我确实尝试将checkAdjacentervals设置为5,我能够验证google authenticator代码,但如前所述,它验证了过去的代码,这在我的情况下是不正确的


因此,我们已通过使用NTP正确同步服务器来更正服务器的时间,然后它开始按预期工作。

我知道这是一个老问题,但它可能会帮助像我这样前来寻找答案的其他人。Google身份验证基于时间。API将基于时间验证过去最近生成的代码(标记它,这是时间,而不是时区)。因此,如果系统的实际时间与生成代码的设备不同步,则会出现问题。特别是,当系统时间落后于设备时间时。如果要验证我的答案,请尝试输入一些旧代码(基于系统和设备之间的连接间隙)。CheckAdjaceEnterVals将在您的系统领先于设备时对您有所帮助,但在设备落后时则不会。我删除了以前关于从不检查基本密码的评论
GetPassword(secret)
我知道现在它在for循环之前,我以前错过了:)你试过使用更高的检查相邻间隔吗?我试过为检查相邻间隔设置10,但当我这样做时,它甚至成功地验证了过去的代码,这意味着代码每30秒都在更改,因此过去30秒的代码也得到了成功验证。我不确定这是否是正确的方法,因为它是wo factor auth和我们正在做额外的验证,只是出于安全目的。确实如此,但我认为这就是checkAdjacentIntervals的目的-考虑客户端和服务器之间的小时间差异。您可能会将其缩小到10以下,但1可能不够。这种双因素身份验证方法(不检查相邻间隔)将要求客户端和服务器在30秒的误差范围内始终对时间有相同的理解。这似乎很难实现。谢谢@Kritner。我听说NTP可用于同步时间。你知道如何在服务器上进行同步吗?