Como posso implementar uma ligação de Reset de senha

tenho actualmente um sistema em que, se um utilizador se esqueceu da sua senha, pode reiniciá-la clicando num link de senha que se esqueceu. Ele será levado para uma página onde insira seu nome de usuário/email e, em seguida, um email será enviado para o usuário, eu queria saber como posso implementar um link de redefinição de senha no e-mail assim que uma vez que o usuário clica no link, ele/ela é levado a uma página que irá permitir-lhes para redefinir sua senha.

Este é o código no meu controlador.

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

Este é o meu procedimento actual armazenado que envia ao Utilizador um e-mail

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
Author: Karan Ramchandani, 2015-03-12

1 answers

Crie uma tabela que tenha uma estrutura como

create table ResetTickets(
    username varchar(200),
    tokenHash varbinary(16),
    expirationDate datetime,
    tokenUsed bit)

, em Seguida, em seu código quando o usuário clicar em repor palavra-passe de botão você irá gerar um token aleatório, em seguida, colocar uma entrada na tabela com o valor de hash que token e uma data de expiração de algo como DATEADD(day, 1, GETDATE()) e acrescenta que o valor do token no url de e-mail para o usuário para a página de redefinição de senha.

www.example.com/passwordReset?username=Karan&token=ZB71yObR

Na página de reset da senha, você pega no nome do utilizador e no token passado, volta a usar o token. compare isso com a tabela ResetTickets, e se a data de expiração ainda não tiver passado e o token ainda não tiver sido usado, então leve o Usuário para uma página que lhes permita digitar uma nova senha.

Coisas com que ter cuidado:

  1. certifique-se de expirar o token, não deixe um e-mail de dois anos atrás reiniciar a senha.
  2. certifique-se de marcar o token como usado, não deixe que outros usuários do computador use o histórico do navegador para reiniciar outros senha.
  3. certifique-se que gera o símbolo aleatório com segurança . Não use Rand e use-o para gerar o item, dois utilizadores que reinicializam ao mesmo tempo obteriam o mesmo item (eu poderia repor a minha senha e a sua senha ao mesmo tempo e, em seguida, usar o meu item para repor a sua conta). Em vez disso, faça uma estática RNGCryptoServiceProvider e use o método GetBytes a partir disso, a classe é Segura thread para que você não precisa se preocupar com dois threads usando a mesma instância.
  4. Be claro que parameteriza as tuas perguntas . no seu código actual, se eu digitasse no userid {[8] } iria apagar todos os utilizadores da sua base de dados. Veja o link SO post para mais informações sobre como corrigi-lo.
  5. certifique-se que anula o item, a sua Página passwordReset só aceita a versão não lavada, e nunca armazena a versão não lavada em lado nenhum (incluindo os registos de E-mail das mensagens enviadas para os utilizadores). Isso impede que um atacante que tenha acesso ao banco de dados de fazer um token para algum outro usuário, lendo o valor que foi enviado no e-mail, em seguida, enviando o mesmo valor ele mesmo (e talvez obter acesso a um usuário administrador que pode fazer mais coisas do que apenas ler valores).
 24
Author: Scott Chamberlain, 2017-05-23 11:47:04