私はグッファの答えが好きです。コメントできないので、ここでウディルの質問に答えます。
同様のものが必要でしたが、トークンに特定のロジックが必要でした。
- トークンの有効期限を確認する
- GUID を使用して検証をマスクする (グローバル アプリケーション GUID またはユーザー GUID)
- トークンが作成した目的のために提供されたかどうかを確認します (再利用はありません..)
- トークンを送信したユーザーが、トークンを検証しているユーザーであるかどうかを確認します
ポイント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(2).ToArray();
byte[] _Id = data.Skip(26).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;
}
private static string GetString(byte[] reason) => Encoding.ASCII.GetString(reason);
private static byte[] GetBytes(string reason) => Encoding.ASCII.GetBytes(reason);
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 時間ほどリストに保持する必要はありません。これが私のGood-Case Unitテストです:
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");
}
コードを他のビジネス ケースに簡単に適応させることができます。
ハッピーコーディング
ウォルター