English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Недавно разрабатывал систему, в которой была потребность - восстанавливать пароль через электронную почту. В текущей системе при регистрации обязательно вводится адрес электронной почты, одна из целей - привязка к почте для возможности восстановления пароля. О функциях отправки почты на 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 (при отправке письма замените # на @) для сообщения о нарушении и предоставьте соответствующие доказательства. Если будет установлено, что содержимое нарушает авторские права, сайт немедленно удалят涉嫌侵权的内容。