Kar*_*ani 13 c# sql-server visual-studio-2010 password-recovery
我目前有一个系统,如果用户忘记了密码,他们可以通过点击忘记密码链接重置密码.他们将被带到他们输入用户名/电子邮件的页面,然后会向用户发送一封电子邮件,我想知道如何在电子邮件中实现密码重置链接,以便用户点击链接后/她被带到一个页面,允许他们重置密码.
这是我控制器中的代码
public ActionResult ForgotPassword()
{
//verify user id
string UserId = Request.Params ["txtUserName"];
string msg = "";
if (UserId == null)
{
msg = "You Have Entered An Invalid UserId - Try Again";
ViewData["ForgotPassword"] = msg;
return View("ForgotPassword");
}
SqlConnection lsql = null;
lsql = DBFactory.GetInstance().getMyConnection();
String sqlstring = "SELECT * from dbo.[USERS] where USERID = '" + UserId.ToString() + "'";
SqlCommand myCommand = new SqlCommand(sqlstring, lsql);
lsql.Open();
Boolean validUser;
using (SqlDataReader myReader = myCommand.ExecuteReader())
{
validUser = false;
while (myReader.Read())
{
validUser = true;
}
myReader.Close();
}
myCommand.Dispose();
if (!validUser)
{
msg = "You Have Entered An Invalid UserId - Try Again";
ViewData["ForgotPassword"] = msg;
lsql.Close();
return View("ForgotPassword");
}
//run store procedure
using (lsql)
{
SqlCommand cmd = new SqlCommand("Stock_Check_Test.dbo.RESET_PASSWORD", lsql);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter paramUsername = new SqlParameter("@var1", UserId);
cmd.Parameters.Add(paramUsername);
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
if (Convert.ToInt32(rdr["RC"]) == 99)
{
msg = "Unable to update password at this time";
ViewData["ForgotPassword"] = msg;
lsql.Close();
return View("ForgotPassword");
}
}
}
msg = "new password sent";
ViewData["ForgotPassword"] = msg;
lsql.Close();
return View("ForgotPassword");
}
Run Code Online (Sandbox Code Playgroud)
这是我当前的存储过程,它向用户发送电子邮件
ALTER PROCEDURE [dbo].[A_SEND_MAIL]
@var1 varchar (200), -- userid
@var2 varchar (200) -- email address
AS
BEGIN
declare @bodytext varchar(200);
set @bodytext = 'Password Reset for user: ' +@var1 + ' @' + cast (getDate() as varchar) + ' ' ;
EXEC msdb.dbo.sp_send_dbmail
@profile_name='Test',
@recipients=@var2,
@subject='Password Reset',
@body=@bodytext
END
GO
Run Code Online (Sandbox Code Playgroud)
Sco*_*ain 28
创建一个具有类似结构的表
create table ResetTickets(
username varchar(200),
tokenHash varbinary(16),
expirationDate datetime,
tokenUsed bit)
Run Code Online (Sandbox Code Playgroud)
然后在您的代码中,当用户单击重置密码按钮时,您将生成一个随机令牌,然后在该表中放入一个带有哈希值的条目token和一个类似的过期日期,DATEADD(day, 1, GETDATE())并将该标记值附加到您通过电子邮件发送到该网址的URL上.用户进行密码重置页面.
www.example.com/passwordReset?username=Karan&token=ZB71yObR
Run Code Online (Sandbox Code Playgroud)
在密码重置页面上,您获取传入的用户名和令牌,再次对令牌进行哈希,然后将其与ResetTickets表进行比较,如果到期日期尚未过期且令牌尚未使用,则将用户带到页面让他们输入一个新密码.
需要注意的事项:
Rand并使用它来生成令牌,同时重置的两个用户将得到相同的令牌(我可以同时重置我的密码和密码,然后使用我的令牌重置您的帐户).而是创建一个静态RNGCryptoServiceProvider并使用该GetBytes方法,该类是线程安全的,因此您不必担心使用相同实例的两个线程.'; delete dbo.[USERS] --,它将删除数据库中的所有用户.有关如何解决此问题的详细信息,请参阅链接的SO帖子.passwordReset页面只接受未散列的版本,并且您永远不会将未散列的版本存储在任何位置(包括向用户发送外发消息的电子邮件日志).这可以防止对数据库具有读访问权限的攻击者为其他用户创建令牌,读取电子邮件中发送的值,然后自己发送相同的值(并且可能访问可以执行更多操作的管理员用户而不只是读取值).