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

У меня есть WCF Webservice, который проверяет, действительно ли пользователь действителен.

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

public bool authenticateUserManual(string userName, string password,string language,string token) { if (Membership.ValidateUser(userName,password)) { ////////// string token = ???? ////////// return true; } else { return false; } } 

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

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

 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 } 

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

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

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

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

Теперь точки 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 Errors = new List(); } public enum TokenValidationStatus { Expired, WrongUser, WrongPurpose, WrongGuid } 

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

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

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

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

Вальтер

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

 static Dictionary dic = new Dictionary(); 

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

 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 или нет.

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

Для генерации ключа см. Здесь

Давайте будем гением компьютера.