come generare un token univoco che scade dopo 24 ore?

Ho un servizio Web WCF che controlla se l’utente è valido.

Se l’utente è valido, desidero generare un token che scade dopo 24 ore.

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

Ci sono due possibili approcci; o si crea un valore univoco e si memorizza da qualche parte insieme al tempo di creazione, ad esempio in un database, oppure si inserisce il tempo di creazione all’interno del token in modo che sia ansible decodificarlo in un secondo momento e vedere quando è stato creato.

Per creare un token unico:

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

Esempio di base di creazione di un token univoco contenente un timestamp:

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

Per decodificare il token per ottenere il tempo di creazione:

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

Nota: se è necessario che il token con il timestamp sia sicuro, è necessario crittografarlo. Altrimenti un utente potrebbe capire cosa contiene e creare un falso token.

Mi piace la risposta di Guffa e dato che non posso commentare, fornirò qui la risposta alla domanda di Udil.

Avevo bisogno di qualcosa di simile ma volevo la logica di certein nel mio token, volevo:

  1. Vedi la scadenza di un token
  2. Utilizzare un guid per la convalida della maschera (guida applicativa globale o guida utente)
  3. Verifica se il token è stato fornito per lo scopo in cui l’ho creato (nessun riutilizzo ..)
  4. Verifica se l’utente a cui invio il token è l’utente per il quale convalido

Ora i punti 1-3 sono di lunghezza fissa, quindi è stato facile, ecco il mio codice:

Ecco il mio codice per generare il token:

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

Ecco il mio codice per prendere la stringa di token generata e convalidarla:

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

La class TokenValidation ha questo aspetto:

 public class TokenValidation { public bool Validated { get { return Errors.Count == 0; } } public readonly List Errors = new List(); } public enum TokenValidationStatus { Expired, WrongUser, WrongPurpose, WrongGuid } 

Ora ho un modo semplice per convalidare un token, non c'è bisogno di tenerlo in una lista per 24 ore o giù di lì. Ecco il mio test dell'unità Good Case:

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

È ansible adattare facilmente il codice per altri casi aziendali.

Felice codifica

Walter

Usa il Dictionary per memorizzare il token con timestamp:

 static Dictionary dic = new Dictionary(); 

Aggiungi token con timestamp ogni volta che crei un nuovo token:

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

C’è un timer in esecuzione per rimuovere tutti i token scaduti da 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); } 

Quindi, quando autentichi il token, controlla solo se il token esiste in dic o no.

è necessario memorizzare il token durante la creazione per la prima registrazione. Quando si recuperano i dati dalla tabella di accesso è necessario differenziare la data immessa con la data corrente se è superiore a 1 giorno (24 ore) è necessario visualizzare un messaggio come il token è scaduto.

Per generare la chiave, fare riferimento qui