Solucionado (ver solução)
Solucionado
(ver solução)
5
respostas

Dúvida Token - Esqueci Senha

Boa tarde.

Estou tentando aplicar o desenvolvimento realizado no curso do link Esqueci senha e estou esbarrando no seguinte problema:

Referência de objeto não definida para uma instância de um objeto. Descrição: Ocorreu uma exceção sem tratamento durante a execução da atual solicitação da Web. Examine o rastreamento de pilha para obter mais informações sobre o erro e onde foi originado no código.

Detalhes da Exceção: System.NullReferenceException: Referência de objeto não definida para uma instância de um objeto.

Erro :

Linha 361: Linha 362: Linha 363: var token = await UserManager.GeneratePasswordResetTokenAsync(usuario.Id); Linha 364: if (ModelState.IsValid) Linha 365: {

Estou com problemas na hora de gerar o token. Já consigo enviar o e-mail e neste e-mail de confirmação clico em um link onde digito a nova senha e clico em Alterar(aqui chamo a função ResetPasswordAsync).

Veja o código onde ocorre o erro:

 [HttpPost]
    public async Task<ActionResult> ConfirmacaoEsqueciSenha(ConfirmacaoEsqueciSenhaViewModel modelo)
    {

        UsuarioManager manager = HttpContext.GetOwinContext().GetUserManager<UsuarioManager>();
        var usuario = await manager.FindByIdAsync(modelo.UsuarioId);



        var token = await UserManager.GeneratePasswordResetTokenAsync(usuario.Id);
        if (ModelState.IsValid)
        {
                var resultadoAlteracao =
                await manager.ResetPasswordAsync(
                    usuario.Id,
                    modelo.Token,
                    modelo.NovaSenha);

            if (resultadoAlteracao.Succeeded)
            {
                return RedirectToAction("Index", "Home");
            }
            AddErrors(resultadoAlteracao);

        }

        return View();
    }

Não estou sabendo lidar com este token. No meu projeto tenho uma classe IdentityConfig, onde tenho informações do UserTokenProvider, mas não sei se tenho que associá-la.

Alguém pode me ajudar. Desde já agradeço.

Flávia Lares

5 respostas

Bom dia. Ainda não consegui resolver. Alguém poderia me ajudar com este erro de token inválido no procedimento de Esqueci senha.

solução!

Bom dia pessoal.

Consegui evoluir com o problema de token inválido. Tive que acrescentar o seguinte código:

[HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> EsqueciSenha(EsqueciSenhaViewModel modelo)
        {
            if (!ModelState.IsValid)
            {
                return View(modelo);
            }
           // UsuarioManager manager = HttpContext.GetOwinContext().GetUserManager<UsuarioManager>();
          //  var usuario = await manager.FindByEmailAsync(modelo.Email);

            var provider = new DpapiDataProtectionProvider("ASP.NET Identity");

            var userManager = HttpContext.GetOwinContext().GetUserManager<UsuarioManager>();

           // var userManager = new UserManager<Usuario>(new UserStore<Usuario>());

            userManager.UserTokenProvider = new DataProtectorTokenProvider<Usuario, string>(
                provider.Create("Igs2.0"));

            var usuario = await userManager.FindByEmailAsync(modelo.Email);


            if (usuario == null || !(await userManager.IsEmailConfirmedAsync(usuario.Id)))
            {
                var token = await userManager.GeneratePasswordResetTokenAsync(usuario.Id);


                var callbackUrl = Url.Action("ConfirmacaoEsqueciSenha", "Autenticacao", new { UsuarioId = usuario.Id, Token= token }, protocol: Request.Url.Scheme);
                var enviarEmail = EmailEsqueciSenhaController.EnviarEmail(usuario, "Por favor redefina sua senha clicando aqui: <a href=\"" + callbackUrl + "\">Clique aqui para redefinir sua senha!</a>", "Alteração de senha");


                return View("EmailEsqueciSenhaEnviado");
            }

            return View(modelo);

        }

Desta forma consigo pegar um token válido e recebo um e-mail para confirmar o reset de senha. Neste e-mail tenho um link que ao clicar, sou redirecionada para o seguinte código:

  [HttpPost]
        public async Task<ActionResult> ConfirmacaoEsqueciSenha(ConfirmacaoEsqueciSenhaViewModel modelo)
        {

        UsuarioManager manager = HttpContext.GetOwinContext().GetUserManager<UsuarioManager>();
        //var usuario = await manager.FindByIdAsync(modelo.UsuarioId);

        if (ModelState.IsValid)
        {
            var resultadoAlteracao =
                await manager.ResetPasswordAsync(
                    modelo.UsuarioId, 
                    modelo.Token,
                    modelo.NovaSenha);

            if (resultadoAlteracao.Succeeded)
            {
                return RedirectToAction("Index", "Home");
            }
            AddErrors(resultadoAlteracao);

        }

        return View();
    }

Na depuração na linha da variável "resultadoAlteracao" estou recebendo todos os dados do modelo(UsuarioId, Token e NovaSenha), sendo que quando passo desta linha ocorre o seguinte erro:

System.NotSupportedException: No IUserTokenProvider is registered.


Linha 343:                //  Verifica o ID do usuário
Linha 344:                // Mudar a senha
Linha 345:                var resultadoAlteracao =
Linha 346:                    await manager.ResetPasswordAsync(
Linha 347:                        modelo.UsuarioId, 

Alguém poderia me ajudar? Obrigada. Flávia Lares

Oi pessoal.

Caso eu coloque este código no construtor do UserManager, assim:

var dataProtectorProvider = IdentityConfig.DataProtectionProvider; var dataProtector = dataProtectorProvider.Create("UserToken"); this.UserTokenProvider = new DataProtectorTokenProvider<Usuario, string>(dataProtector) { TokenLifespan = TimeSpan.FromHours(24), };

Quando chego neste código:

[HttpPost] public async Task ConfirmacaoEsqueciSenha(ConfirmacaoEsqueciSenhaViewModel modelo) {

        if (ModelState.IsValid)
        {
            // Verifica o Token recebido
            //  Verifica o ID do usuário
            // Mudar a senha
            var resultadoAlteracao =
                await UserManager.ResetPasswordAsync(
                    modelo.UsuarioId,
                    HttpUtility.UrlDecode(modelo.Token),
                    modelo.NovaSenha);

            if (resultadoAlteracao.Succeeded)
            {
                return RedirectToAction("Index", "Home");
            }

            AddErrors(resultadoAlteracao);

    }

        return View();
}

Na variável resultadoAlteracao recebo o erro de Token Inválido. Como estou colocando o código no construtor, acredito que neste momento do erro ele está criando um novo usuário e invalidando o token.

Onde colocar este código do token?

Obrigada. Flávia Lares

Oi Flávia, tudo bem?

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EsqueciSenha(EsqueciSenhaViewModel modelo)
{
    if (!ModelState.IsValid)
    {
        return View(modelo);
    }

    var provider = new DpapiDataProtectionProvider("ASP.NET Identity");
    var userManager = HttpContext.GetOwinContext().GetUserManager<UsuarioManager>();
    userManager.UserTokenProvider = new DataProtectorTokenProvider<Usuario, string>(
        provider.Create("Igs2.0"));

    //var usuario = await userManager.FindByEmailAsync(modelo.Email);
    var usuario = await UserManager.FindByNameAsync(model.Email);
    if (usuario == null || !(await UserManager.IsEmailConfirmedAsync(usuario.Id)))
    {
        // Don't reveal that the user does not exist or is not confirmed
        return View("ConfirmacaoEsqueciSenha");
    }

    var token = await UserManager.GeneratePasswordResetTokenAsync(usuario.Id);
    var callbackUrl = Url.Action("ConfirmacaoEsqueciSenha", "Autenticacao", new { UsuarioId = usuario.Id, Token = token }, protocol: Request.Url.Scheme);
    var enviarEmail = EmailEsqueciSenhaController.EnviarEmail(usuario, "Por favor redefina sua senha clicando aqui: <a href=\"" + callbackUrl + "\">Clique aqui para redefinir sua senha!</a>", "Alteração de senha");        
    return View("EmailEsqueciSenhaEnviado");
}

Seguindo o exemplo da documentação da Microsoft, fiz umas alterações no código do método EsqueciSenha().

Por favor, comente ou salve seu código, e adicione este. As diferenças estão do método FindByEmailAsync(), que foi substituído por FindByNameAsync(), e na instrução if, onde é verificado se usuario == null.

Oi Marcelo, tudo bem e com vc?

Testei o código que vc mandou e não funcionou com :

var usuario = await UserManager.FindByNameAsync(modelo.Email);

Neste caso o usuário é nulo. Continuei com o código:

var usuario = await UserManager.FindByEmailAsync(modelo.Email);

Para testar a lógica que me enviou.

Desta forma ocorre um outro erro no código:

[HttpPost] public async Task ConfirmacaoEsqueciSenha(ConfirmacaoEsqueciSenhaViewModel modelo) {

        if (ModelState.IsValid)
        {
            // Verifica o Token recebido
            //  Verifica o ID do usuário
            // Mudar a senha
            var resultadoAlteracao =
                await UserManager.ResetPasswordAsync(
                    modelo.UsuarioId,
                    modelo.Token,
                    modelo.NovaSenha);

            if (resultadoAlteracao.Succeeded)
            {
                return RedirectToAction("Index", "Home");
            }

            AddErrors(resultadoAlteracao);

    }

        return View();
}

Segue abaixo o erro que ocorre:

No IUserTokenProvider is registered. Descrição: Ocorreu uma exceção sem tratamento durante a execução da atual solicitação da Web. Examine o rastreamento de pilha para obter mais informações sobre o erro e onde foi originado no código.

Detalhes da Exceção: System.NotSupportedException: No IUserTokenProvider is registered.

Erro de Origem:

Linha 353: // Verifica o ID do usuário Linha 354: // Mudar a senha Linha 355: var resultadoAlteracao = Linha 356: await UserManager.ResetPasswordAsync( Linha 357: modelo.UsuarioId,

É como se o usuário não estivesse registrado. Sabe o que pode ser?

Obrigada. Flávia Lares