我如何验证电子邮件确认令牌?
How can i validate email confirmation token?
在我的 asp.net mvc 应用程序中,当用户注册时,我会向他们的帐户发送一封电子邮件,其中包含 link 进行验证,然后他们才能使用该应用程序。请参阅下面的代码片段。
var emailActionLink = Url.Action("ValidateAccount", "Register",
new { Token = registeredUserViewModel.Id, Username = registeredUserViewModel.Username },
Request.Url.Scheme);
上面的代码片段是他们将点击的内容,然后将使用路由值调用操作,
验证帐户操作
public ActionResult ValidateAccount(string token, string username)
{
try
{
if (!string.IsNullOrEmpty(token) && !string.IsNullOrEmpty(username))
{
var user = _userServiceClient.IsUserNameAvailable(username);
if (!user.HasValue) throw new NullReferenceException("This account does not exist");
var userContract = user.Value;
userContract.EmailVerified = true;
if (_userServiceClient.UpdateUser(userContract) == null) throw new Exception("Something has gone wrong");
return View("ValidationCompleted");
}
else
{
ViewBag.RegisteredUser = null;
}
}
catch (Exception exception)
{
throw;
}
return View();
}
问题是,这个方法没有验证token,如果有人改变了uri中token
的值会发生什么,这仍然会通过并且非常账户。改进这一点的正确方法是什么。
在这种情况下,token 是用户的 Id,它是一个 Guid,但它是经过编码的,无法将我数据库中的用户 Id 与此编码的 token 进行比较。我认为这是在动作 link.
中编码的
与其使用您的 Id,不如在 table 中有一个 Token 字段(可为空,以便在验证后将其清除)可能会更好。生成一个 URL 安全令牌(我使用十六进制字符串,不使用任何特殊字符),然后在验证操作中在数据库中查找该令牌。
这是令牌生成器的示例:
public class TokenGenerator
{
public static string GenerateToken(int size = 32)
{
var crypto = new RNGCryptoServiceProvider();
byte[] rbytes = new byte[size / 2];
crypto.GetNonZeroBytes(rbytes);
return ToHexString(rbytes, true);
}
private static string ToHexString(byte[] bytes, bool useLowerCase = false)
{
var hex = string.Concat(bytes.Select(b => b.ToString(useLowerCase ? "x2" : "X2")));
return hex;
}
}
然后,将适当的方法添加到您的服务中 class:
public YourUserType GetUserForToken(string token, string userName)
{
return YourDbContext.Users
.SingleOrDfault(user => user.Token.Equals(token, StringComparison.OrdinalIgnoreCase)
&& user.UserName.Equals(userName, StringComparison.OrdinalIgnoreCase));
}
显然,这对您的 table 结构和数据访问代码做了一些假设。
在我的 asp.net mvc 应用程序中,当用户注册时,我会向他们的帐户发送一封电子邮件,其中包含 link 进行验证,然后他们才能使用该应用程序。请参阅下面的代码片段。
var emailActionLink = Url.Action("ValidateAccount", "Register",
new { Token = registeredUserViewModel.Id, Username = registeredUserViewModel.Username },
Request.Url.Scheme);
上面的代码片段是他们将点击的内容,然后将使用路由值调用操作,
验证帐户操作
public ActionResult ValidateAccount(string token, string username)
{
try
{
if (!string.IsNullOrEmpty(token) && !string.IsNullOrEmpty(username))
{
var user = _userServiceClient.IsUserNameAvailable(username);
if (!user.HasValue) throw new NullReferenceException("This account does not exist");
var userContract = user.Value;
userContract.EmailVerified = true;
if (_userServiceClient.UpdateUser(userContract) == null) throw new Exception("Something has gone wrong");
return View("ValidationCompleted");
}
else
{
ViewBag.RegisteredUser = null;
}
}
catch (Exception exception)
{
throw;
}
return View();
}
问题是,这个方法没有验证token,如果有人改变了uri中token
的值会发生什么,这仍然会通过并且非常账户。改进这一点的正确方法是什么。
在这种情况下,token 是用户的 Id,它是一个 Guid,但它是经过编码的,无法将我数据库中的用户 Id 与此编码的 token 进行比较。我认为这是在动作 link.
中编码的与其使用您的 Id,不如在 table 中有一个 Token 字段(可为空,以便在验证后将其清除)可能会更好。生成一个 URL 安全令牌(我使用十六进制字符串,不使用任何特殊字符),然后在验证操作中在数据库中查找该令牌。
这是令牌生成器的示例:
public class TokenGenerator
{
public static string GenerateToken(int size = 32)
{
var crypto = new RNGCryptoServiceProvider();
byte[] rbytes = new byte[size / 2];
crypto.GetNonZeroBytes(rbytes);
return ToHexString(rbytes, true);
}
private static string ToHexString(byte[] bytes, bool useLowerCase = false)
{
var hex = string.Concat(bytes.Select(b => b.ToString(useLowerCase ? "x2" : "X2")));
return hex;
}
}
然后,将适当的方法添加到您的服务中 class:
public YourUserType GetUserForToken(string token, string userName)
{
return YourDbContext.Users
.SingleOrDfault(user => user.Token.Equals(token, StringComparison.OrdinalIgnoreCase)
&& user.UserName.Equals(userName, StringComparison.OrdinalIgnoreCase));
}
显然,这对您的 table 结构和数据访问代码做了一些假设。