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 example: 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 = "用户名不存在,你不会忘记用户名了吧&63;"; 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); //保存到数据库 String key = users.getUserName()+"$"+date+"$"+secretKey; String digitalSignature = MD5.MD5Encode(key); //디지털 서명 String emailTitle = "有方云密码找回"; 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 = "이 이메일에 답변하지 마세요. 아래의 링크를 클릭하여 비밀번호를 재설정하십시오<br/><a href="+resetPassHref +" target='_BLANK'>링크를 클릭하여 비밀번호를 다시 설정하십시오</a>" + "<br/>힌트: 이 이메일은30분 후, 링크가 만료되며, 다시 "비밀번호 찾기"를 신청해야 합니다"+key;+"\t"+digitalSignature; System.out.print(resetPassHref); SendMail.getInstatnce().sendHtmlMail(emailTitle,emailContent,users.getEmail()); msg = "操作成功,已经发送找回密码链接到您的邮箱。请在30분 내에 비밀번호를 재설정하세요"; logInfo(request,userName,"비밀번호 재설정 신청"); } e.printStackTrace(); msg="이메일이 없습니다? 불명확한 오류, 관리자에게 연락하세요。"; } 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="링크가 불 completo, 다시 생성하세요"; 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 = "링크가 잘못되었습니다, 만료되었습니까?"63다시 신청하세요"; 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 아래 title 중국어 비켜침 문제 해결
sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
mailMessage.setSubject(MimeUtility.encodeText(mailInfo.getSubject(), "UTF-8", "B"); //linux 메일 제목의 비켜침 문제 해결
보완3:왜 sid를 user 테이블에 직접 삽입하지 않을까요? 검증할 때 sid를 비교하면 됩니다.
이것이 이 문서의 전체 내용입니다. 여러분의 학습에 도움이 되길 바랍니다. 또한, 나아가呐喊 강의를 많이 지지해 주시길 바랍니다.
성명서:이 문서의 내용은 인터넷에서 수집되었습니다. 저작권은 원저자에게 있으며, 인터넷 사용자가 자발적으로 기여하고 자체로 업로드한 내용입니다. 이 사이트는 소유권을 가지지 않으며, 인공 편집을 하지 않았으며, 관련 법적 책임을 부담하지 않습니다. 저작권 문제가 있을 경우, notice#w로 이메일을 보내 주시기 바랍니다.3codebox.com(이메일을 보내는 경우, #을 @으로 변경하십시오. 신고를 제공하고 관련 증거를 제공하면, 해당 사이트는 즉시 의심스러운 저작권 내용을 삭제합니다。)