English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Implementación de la función de recuperación de contraseña mediante correo electrónico en SpringMVC

最近开发一个系统,有一个需求就是,忘记密码后通过邮箱找回。现在的系统在注册时都会强制输入邮箱,其中一个目的就是通过邮件绑定找回,可以进行密码找回。通过Java发送邮件的功能我就不说了,重点讲找回密码。

参考别人的思路:发送邮件→请求邮件中的URL→验证url→{验证成功修改密码,不成功跳转到失败页面}

重点是生成这个url和解析这个url的方法。
需要注意的是一个url只能修改一次密码,当同一账号发送多封邮件时,只有最后一封邮件的url

 加密可以防止伪造攻击,一次url只能验证一次,并且绑定了用户。生成url: 可以使用UUID生成随机密钥。

数字签名 = MD5(用户名+'$'+过期时间+‘$'+密钥key)

数据库字段(用户名(主键),密钥key,过期时间)

url参数(用户名,数字签名),密钥key的生成:在每一个用户找回密码时为该用户生成一个密钥key ,

url示例: http://localhost:8080/user/reset_password#63;sid=D622D6A23FBF86FFE696B593D55351A54AEAEA77&userName=test4

生成过期时间,生成数字签名,生成url,发送邮件. 保存或更新(用户名,密钥key,过期时间)

以下为springMvc代码

@RequestMapping(value = "/user/i_forget_password")
  @ResponseBody
  public Map forgetPass(HttpServletRequest request,String userName){
    Users users = userService.findUserByName(userName);
    Map map = new HashMap<String ,String>();
    String msg = "";
    if(users == null){       //El nombre de usuario no existe
      msg = "El nombre de usuario no existe, ¿no recuerda su nombre de usuario?&63;";
      map.put("msg",msg);
      return map;
    }
    try{
      String secretKey= UUID.randomUUID().toString(); //clave
      Timestamp outDate = new Timestamp(System.currentTimeMillis();+30*60*1000);//3vence en 0 minutos
      long date = outDate.getTime();/1000*1000;         //ignorar los milisegundos
      users.setValidataCode(secretKey);
      users.setRegisterDate(outDate);
      userService.update(users);  //guardar en la base de datos
      String key = users.getUserName()+"$"+date+"$"+secretKey;
      String digitalSignature = MD5.MD5Encode(key);         //Firma digital
      String emailTitle = "Recuperación de contraseña de Yifang Cloud";
      String path = request.getContextPath();
      String basePath = request.getScheme();+://"+request.getServerName();+:"+request.getServerPort();+path+"/";
      String resetPassHref = basePath;+"user/reset_password#63;sid="+digitalSignature;+"&userName="+users.getUserName();
      String emailContent = "No responder a este correo electrónico. Haga clic en el siguiente enlace para restablecer su contraseña<br/><a href="+resetPassHref; +" target='_BLANK'>Haga clic aquí para restablecer su contraseña</a>" +
          "<br/>Consejo: Este correo electrónico ha superado30 minutos, el enlace caducará y tendrá que solicitar nuevamente la 'recuperación de contraseña'."+key;+"\t"+digitalSignature;
      System.out.print(resetPassHref);
      SendMail.getInstatnce().sendHtmlMail(emailTitle, emailContent, users.getEmail());
      msg = "Operación exitosa, se ha enviado un enlace de recuperación de contraseña a su correo electrónico. Por favor, en"3Restablecer contraseña en 0 minutos";
      logInfo(request,userName,"Solicitud de recuperación de contraseña");
    }
      e.printStackTrace();
      msg="Correo electrónico no existe? Error desconocido, contacte al administrador.";
    }
    map.put("msg",msg);
    return map;
  }

El enlace de recuperación ha sido enviado al correo electrónico. Ingrese al correo electrónico y abra el enlace

El siguiente es el código de verificación del enlace, si pasa, se saltará a la interfaz de cambio de contraseña, de lo contrario, se saltará a la interfaz de fracaso

@RequestMapping(value = "/user/reset_password",method = RequestMethod.GET)
  public ModelAndView checkResetLink(String sid,String userName){
    ModelAndView model = new ModelAndView("error");
    String msg = "";
    if(sid.equals("") || userName.equals("")){
      msg="Enlace incompleto, generelo nuevamente";
      model.addObject("msg",msg) ;
      logInfo(userName,"El enlace de recuperación de contraseña ha caducado");
      return model;
    }
    Users users = userService.findUserByName(userName);
    if(users == null){
      msg = "Enlace incorrecto, no se encontró usuario correspondiente, solicite nuevamente para recuperar la contraseña.";
      model.addObject("msg",msg) ;
      logInfo(userName,"El enlace de recuperación de contraseña ha caducado");
      return model;
    }
    Timestamp outDate = users.getRegisterDate();
    if(outDate.getTime() <= System.currentTimeMillis()){     //Indica que ha caducado
      msg = "El enlace ha caducado, solicite nuevamente para recuperar la contraseña.";
      model.addObject("msg",msg) ;
      logInfo(userName,"El enlace de recuperación de contraseña ha caducado");
      return model;
    }
    String key = users.getUserName()+"$"+outDate.getTime()/1000*1000+"$"+users.getValidataCode();     //Firma digital
    String digitalSignature = MD5.MD5Encode(key);
    System.out.println(key+"\t"+digitalSignature);
    if(!digitalSignature.equals(sid)) {
      msg = "El enlace no es correcto, ¿ha caducado ya?&"63;Vuelva a solicitarlo";
      model.addObject("msg",msg) ;
      logInfo(userName,"El enlace de recuperación de contraseña ha caducado");
      return model;
    }
    model.setViewName("user/reset_password"); //Volver a la interfaz de cambio de contraseña
    model.addObject("userName",userName);
    return model;
  }

Suplemento1:El objeto de tipo Timestamp pierde la precisión de milisegundos al guardarse. Por ejemplo:2013-10-08 10:29:10.234 Al almacenar en la base de datos mysql se convierte en 2013-10-08 10:29:10.0. El tiempo se vuelve diferente, cuando sid coincide no será igual. Por lo tanto, hice la operación de ignorar la precisión.

Suplemento2:Solución al mal código de título chino en Linux

sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
mailMessage.setSubject(MimeUtility.encodeText(mailInfo.getSubject(), "UTF-8", "B");      //Solución al mal código de correo electrónico de título en Linux

Suplemento3:¿Por qué no insertar directamente sid en la tabla user? La verificación se realiza directamente comparando sid, así es suficiente.

Esto es todo el contenido de este artículo, espero que sea útil para su aprendizaje y que todos nos apoyen en el tutorial de clamor.

Declaración: el contenido de este artículo se obtiene de la red, es propiedad del autor original, el contenido se contribuye y sube por los usuarios de Internet de manera autónoma, este sitio no posee los derechos de propiedad, no se ha realizado un procesamiento editorial humano y no asume ninguna responsabilidad legal relacionada. Si encuentra contenido sospechoso de copyright, le invitamos a enviar un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @) para denunciar, y proporcione evidencia relevante. Una vez verificada, este sitio eliminará inmediatamente el contenido sospechoso de infracción.

Te gustará