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

Реализация функции восстановления пароля через почту в SpringMVC

Недавно разрабатывал систему, в которой была потребность - восстанавливать пароль через электронную почту. В текущей системе при регистрации обязательно вводится адрес электронной почты, одна из целей - привязка к почте для возможности восстановления пароля. О функциях отправки почты на Java я не буду говорить,重点在于 восстановление пароля.

Референция к思路 других: отправка электронной почты→просьба о URL в письме→проверка URL→{если проверка успешна, изменить пароль, если нет, перейти на страницу неудачи}

Основное внимание уделяется тому, как генерировать этот url и как интерпретировать этот url.
Следует отметить, что один url можно изменить только один раз. Если для одного и того же счета отправлено несколько писем, только url последнего письма

 Шифрование может предотвратить поддельные атаки, один url может быть проверен только один раз, и он привязан к пользователю. Генерация url: можно использовать UUID для генерации случайного ключа.

Цифровая подпись = MD5(имя пользователя+'$'+время действия+‘$’+ключ key)

Поле базы данных (имя пользователя (первичный ключ), ключ key, время действия)

Параметры url (имя пользователя, цифровая подпись) , генерация ключа key: При каждом запросе на восстановление пароля для этого пользователя генерируется ключ key ,

Пример url: http://localhost:8080/user/reset_password?sid=D622D6A23FBF86FFE696B593D55351A54AEAEA77&userName=test4

Генерация времени действия, генерация цифровой подписи, генерация url, отправка электронной почты. saveOrUpdate(имя пользователя, ключ 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){       //Пользователь с таким именем не существует
      msg = "Пользователь с таким именем не существует, не забыли ли вы имя пользователя?";
      map.put("msg",msg);}
      return map;
    }
    try{
      String secretKey= UUID.randomUUID().toString(); //Ключ
      Timestamp outDate = new Timestamp(System.currentTimeMillis()+30*60*1000);//Срок действия через 30 минут
      long date = outDate.getTime()/1000*1000;         //Пропускать миллисекунды
      users.setValidataCode(secretKey);
      users.setRegisterDate(outDate);
      userService.update(users);  //Saved to database
      String key = users.getUserName()+"$"+date+"$"+secretKey;
      String digitalSignature = MD5.MD5Encode(key);         //Digital signature
      String emailTitle = "Youfang Cloud Password Recovery";
      String path = request.getContextPath();
      String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
      String resetPassHref = basePath+"user/reset_password?sid="+digitalSignature+"&userName="+users.getUserName();
      String emailContent = "Do not reply to this email. Click the link below to reset your password<br/><a href="+resetPassHref +" target='_BLANK'>Click here to reset your password</a>" +
          "<br/>tips: This email has exceeded 30 minutes, the link will expire, and you need to reapply for 'password recovery'"+key+"\t"+digitalSignature;
      System.out.print(resetPassHref);
      SendMail.getInstatnce().sendHtmlMail(emailTitle, emailContent, users.getEmail());
      msg = "Operation successful, the password recovery link has been sent to your email. Please reset your password within 30 minutes.";
      logInfo(request, userName, "Password recovery application");
    }catch (Exception e){
      e.printStackTrace();
      msg="Email not found? Unknown error, please contact the administrator.";
    }
    map.put("msg",msg);}
    return map;
  }

Ссылка для восстановления пароля уже отправлена на почту. Войдите в почту и откройте ссылку

Следующий код проверяет ссылку, если проверка успешна, переход на страницу изменения пароля, в противном случае переход на страницу неудачи

@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="Ссылка неполная, пожалуйста, заново сгенерируйте";
      model.addObject("msg",msg) ;
      logInfo(userName,"Ссылка для восстановления пароля недействительна");
      return model;
    }
    Users users = userService.findUserByName(userName);
    if(users == null){
      msg = "Ошибка ссылки, не удалось найти соответствующего пользователя, пожалуйста, заново запросите восстановление пароля.";
      model.addObject("msg",msg) ;
      logInfo(userName,"Ссылка для восстановления пароля недействительна");
      return model;
    }
    Timestamp outDate = users.getRegisterDate();
    if(outDate.getTime() <= System.currentTimeMillis()){     //Показывает, что срок действия уже истек
      msg = "Ссылка уже истекла, пожалуйста, заново запросите恢复密码.";
      model.addObject("msg",msg) ;
      logInfo(userName,"Ссылка для восстановления пароля недействительна");
      return model;
    }
    String key = users.getUserName()+"$"+outDate.getTime()/1000*1000+"$"+users.getValidataCode();     //Цифровой подпись
    String digitalSignature = MD5.MD5Encode(key);
    System.out.println(key+"\t"+digitalSignature);
    if(!digitalSignature.equals(sid)) {
      msg = "Ссылка incorrect, не истек ли срок действия? Попробуйте заново";
      model.addObject("msg",msg) ;
      logInfo(userName,"Ссылка для восстановления пароля недействительна");
      return model;
    }
    model.setViewName("user/reset_password"); //Вернуться на страницу изменения пароля
    model.addObject("userName",userName);
    return model;
  }

Дополнение 1:Объект типа Timestamp при сохранении в данных теряет миллисекундную точность. Например: 2013-10-08 10:29:10.234 при сохранении в базу данных MySQL становится 2013-10-08 10:29:10.0. Время изменилось, при сравнении sid они не будут равны. Поэтому я сделал операцию игнорирования точности.

Дополнение 2:Устранение проблемы с некорректным отображением заголовка почты на Linux

sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
mailMessage.setSubject(MimeUtility.encodeText(mailInfo.getSubject(), "UTF-8", "B"));      //Устранение проблемы с некорректным отображением заголовка почты на Linux

Дополнение 3:Почему не просто вставить sid в таблицу user. При проверке достаточно сравнить sid.

Вот и все, что есть в этой статье, надеюсь, это поможет вам в изучении.我们也希望大家多多支持呐喊教程。

Заявление: содержание этой статьи взято из Интернета, авторское право принадлежит соответствующему автору, материал предоставлен пользователями Интернета в порядке добровольного вклада и самостоятельной загрузки, сайт не имеет права собственности, не был обработан вручную и не несет ответственности за соответствующие юридические вопросы. Если вы обнаружите подозрительное нарушение авторских прав, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (при отправке письма замените # на @) для сообщения о нарушении и предоставьте соответствующие доказательства. Если будет установлено, что содержимое нарушает авторские права, сайт немедленно удалят涉嫌侵权的内容。

Давай посмотрим, что еще может вам понравиться