Подтвердить что ты не робот

Как создать уникальный токен, срок действия которого истекает через 24 часа?

У меня есть веб-служба WCF, которая проверяет, действителен ли пользователь.

Если пользователь действителен, я хочу сгенерировать токен, срок действия которого истекает через 24 часа.

public bool authenticateUserManual(string userName, string password,string language,string token)
{
    if (Membership.ValidateUser(userName,password))
    {
        //////////
        string token = ???? 
        //////////

        return true;
    }
    else 
    {
        return false;
    }
}   
4b9b3361

Ответ 1

Существует два возможных подхода; либо вы создаете уникальное значение и храните где-то вместе со временем создания, например, в базе данных, или вы помещаете время создания внутри токена, чтобы впоследствии его расшифровать и посмотреть, когда он был создан.

Чтобы создать уникальный токен:

string token = Convert.ToBase64String(Guid.NewGuid().ToByteArray());

Основной пример создания уникального токена, содержащего отметку времени:

byte[] time = BitConverter.GetBytes(DateTime.UtcNow.ToBinary());
byte[] key = Guid.NewGuid().ToByteArray();
string token = Convert.ToBase64String(time.Concat(key).ToArray());

Чтобы декодировать токен, чтобы получить время создания:

byte[] data = Convert.FromBase64String(token);
DateTime when = DateTime.FromBinary(BitConverter.ToInt64(data, 0));
if (when < DateTime.UtcNow.AddHours(-24)) {
  // too old
}

Примечание. Если вам нужен токен с меткой времени для обеспечения безопасности, вам необходимо зашифровать его. В противном случае пользователь может выяснить, что он содержит, и создать ложный токен.

Ответ 2

Мне нравится ответ Гуффа, и, поскольку я не могу комментировать, я предоставлю ответ на вопрос Udil.

Мне нужно что-то подобное, но я хотел, чтобы логика certein в моем токене, я хотел:

  • См. окончание токена
  • Используйте руководство для маскировки validate (глобальное руководство для приложений или пользовательское руководство).
  • Посмотрите, был ли предоставлен токен для цели, которую я создал (без повторного использования..)
  • Посмотрите, является ли пользователь, которому я посылаю токен, пользователю, которого я проверяю для

Теперь точки 1-3 фиксированной длины, так что это было легко, вот мой код:

Вот мой код для генерации токена:

public string GenerateToken(string reason, MyUser user)
{
    byte[] _time     = BitConverter.GetBytes(DateTime.UtcNow.ToBinary());
    byte[] _key      = Guid.Parse(user.SecurityStamp).ToByteArray();
    byte[] _Id       = GetBytes(user.Id.ToString());
    byte[] _reason   = GetBytes(reason);
    byte[] data       = new byte[_time.Length + _key.Length + _reason.Length+_Id.Length];

    System.Buffer.BlockCopy(_time, 0, data, 0, _time.Length);
    System.Buffer.BlockCopy(_key , 0, data, _time.Length, _key.Length);
    System.Buffer.BlockCopy(_reason, 0, data, _time.Length + _key.Length, _reason.Length);
    System.Buffer.BlockCopy(_Id, 0, data, _time.Length + _key.Length+ _reason.Length, _Id.Length);

    return Convert.ToBase64String(data.ToArray());
}

Вот мой код, чтобы взять сгенерированную строку токена и проверить его:

public TokenValidation ValidateToken(string reason, MyUser user, string token)
{
    var result = new TokenValidation();
    byte[] data     = Convert.FromBase64String(token);
    byte[] _time     = data.Take(8).ToArray();
    byte[] _key      = data.Skip(8).Take(16).ToArray();
    byte[] _reason   = data.Skip(24).Take(4).ToArray();
    byte[] _Id       = data.Skip(28).ToArray();

    DateTime when = DateTime.FromBinary(BitConverter.ToInt64(_time, 0));
    if (when < DateTime.UtcNow.AddHours(-24))
    {
        result.Errors.Add( TokenValidationStatus.Expired);
    }

    Guid gKey = new Guid(_key);
    if (gKey.ToString() != user.SecurityStamp)
    {
        result.Errors.Add(TokenValidationStatus.WrongGuid);
    }

    if (reason != GetString(_reason))
    {
        result.Errors.Add(TokenValidationStatus.WrongPurpose);
    }

    if (user.Id.ToString() != GetString(_Id))
    {
        result.Errors.Add(TokenValidationStatus.WrongUser);
    }

    return result;
}

Класс TokenValidation выглядит следующим образом:

public class TokenValidation
{
    public bool Validated { get { return Errors.Count == 0; } }
    public readonly List<TokenValidationStatus> Errors = new List<TokenValidationStatus>();
}

public enum TokenValidationStatus
{
    Expired,
    WrongUser,
    WrongPurpose,
    WrongGuid
}

Теперь у меня есть простой способ проверить токен, нет необходимости хранить его в списке в течение 24 часов или около того. Вот мой пример хорошего Unit test:

private const string ResetPasswordTokenPurpose = "RP";
private const string ConfirmEmailTokenPurpose  = "EC";//change here change bit length for reason  section (2 per char)

[TestMethod]
public void GenerateTokenTest()
{
    MyUser user         = CreateTestUser("name");
    user.Id             = 123;
    user.SecurityStamp  = Guid.NewGuid().ToString();
    var token   = sit.GenerateToken(ConfirmEmailTokenPurpose, user);
    var validation    = sit.ValidateToken(ConfirmEmailTokenPurpose, user, token);
    Assert.IsTrue(validation.Validated,"Token validated for user 123");
}

Можно легко адаптировать код для других бизнес-кейсов.

Счастливое кодирование

Вальтер

Ответ 3

Используйте Dictionary<string, DateTime> для хранения токена с меткой времени:

static Dictionary<string, DateTime> dic = new Dictionary<string, DateTime>();

Добавить маркер с меткой времени при создании нового токена:

dic.Add("yourToken", DateTime.Now);

Существует таймер для удаления любых истекших токенов из dic:

 timer = new Timer(1000*60); //assume run in 1 minute
 timer.Elapsed += timer_Elapsed;

 static void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        var expiredTokens = dic.Where(p => p.Value.AddDays(1) <= DateTime.Now)
                              .Select(p => p.Key);

        foreach (var key in expiredTokens)
            dic.Remove(key);
    }

Итак, когда вы аутентифицируете токен, просто проверьте, существует ли токен в dic или нет.

Ответ 4

вам нужно сохранить токен при создании для первой регистрации. Когда вы извлекаете данные из таблицы входа в систему, вам нужно различать введенную дату с текущей датой, если вам больше 1 дня (24 часа), вам нужно отобразить сообщение, так как ваш токен истек.

Чтобы сгенерировать ключ, обратитесь здесь