I have a WCF Webservice which checks if the user is valid.
If the user is valid I want to generate a token which expires after 24 hours.
public bool authenticateUserManual(string userName, string password,string language,string token)
{
if (Membership.ValidateUser(userName,password))
{
//////////
string token = ????
//////////
return true;
}
else
{
return false;
}
}
This question is related to
c#
asp.net
wcf
authentication
token
This way a token will exist up-to 24 hours. here is the code to generate token which will valid up-to 24 Hours. this code we use but i did not compose it.
public static string GenerateToken()
{
int month = DateTime.Now.Month;
int day = DateTime.Now.Day;
string token = ((day * 100 + month) * 700 + day * 13).ToString();
return token;
}
Use Dictionary<string, DateTime>
to store token with timestamp:
static Dictionary<string, DateTime> dic = new Dictionary<string, DateTime>();
Add token with timestamp whenever you create new token:
dic.Add("yourToken", DateTime.Now);
There is a timer running to remove any expired tokens out of 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);
}
So, when you authenticate token, just check whether token exists in dic or not.
I like Guffa's answer and since I can't comment I will provide the answer Udil's question here.
I needed something similar but I wanted certein logic in my token, I wanted to:
Now points 1-3 are fixed length so it was easy, here is my code:
Here is my code to generate the 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());
}
Here is my Code to take the generated token string and validate it:
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);
The TokenValidation class looks like this:
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
}
Now I have an easy way to validate a token, no Need to Keep it in a list for 24 hours or so. Here is my Good-Case 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");
}
One can adapt the code for other business cases easely.
Happy Coding
Walter
you need to store the token while creating for 1st registration. When you retrieve data from login table you need to differentiate entered date with current date if it is more than 1 day (24 hours) you need to display message like your token is expired.
To generate key refer here
Source: Stackoverflow.com