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 = "用户名不存在,你不会忘记用户名了吧?"; 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,"طلب استعادة كلمة المرور"); }catch (Exception e){ e.printStackTrace(); msg="البريد الإلكتروني غير موجود؟ خطأ غير معروف، يرجى الاتصال بالمدير."; } map.put("msg",msg);}} return map; }
The password recovery link has been sent to the email. Open the link in the email
The following is the link verification code, if verified, jump to the password modification interface, otherwise jump to the failure interface
@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="Link is incomplete, please regenerate"; model.addObject("msg",msg) ; logInfo(userName,"Password recovery link has expired"); return model; } Users users = userService.findUserByName(userName); if(users == null){ msg = "Link error, unable to find matching user, please apply again to recover the password."; model.addObject("msg",msg) ; logInfo(userName,"Password recovery link has expired"); return model; } Timestamp outDate = users.getRegisterDate(); if(outDate.getTime() <= System.currentTimeMillis()){ //Indicates that it has expired msg = "Link has expired, please apply again to recover the password."; model.addObject("msg",msg) ; logInfo(userName,"Password recovery link has expired"); return model; } String key = users.getUserName()+"$"+outDate.getTime()/1000*1000+"$"+users.getValidataCode(); //Digital signature String digitalSignature = MD5.MD5Encode(key); System.out.println(key+"\t"+digitalSignature); if(!digitalSignature.equals(sid)) { msg = "Link is incorrect, has it expired? Apply again"; model.addObject("msg",msg) ; logInfo(userName,"Password recovery link has expired"); return model; } model.setViewName("user/reset_password"); //return to the password modification interface model.addObject("userName",userName); return model; }
إضافة 1:عند حفظ أوبجكت Timestamp في البيانات، يفقد دقة المليون ثانية. على سبيل المثال: 2013-10-08 10:29:10.234 يصبح 2013-10-08 10:29:10.0 عند حفظه في قاعدة بيانات MySQL، مما يجعل الوقت مختلفًا، وسيكون sid غير متطابق عند التحقق. لذلك قمت بتجاهل الدقة.
إضافة 2:حل مشكلة الترميز غير الصحيح في عنوان البريد الإلكتروني في لينكس
sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
mailMessage.setSubject(MimeUtility.encodeText(mailInfo.getSubject(), "UTF-8", "B")); // لحل مشكلة الترميز غير الصحيح في عنوان البريد الإلكتروني في لينكس
إضافة 3:لماذا لا نقوم بتعيين sid مباشرة إلى جدول user؟ في التحقق، يمكن مقارنة sid مباشرة وهو كافٍ.
هذا هو نهاية محتوى المقال، آمل أن يكون قد ساعد في تعلمكم، وأتمنى أن تدعموا تعليمي الموقع.
بيان: محتوى هذا المقال تم جمعه من الإنترنت، حقوق الطبع والنشر تخص صاحب العمل، تم جمع المحتوى من قبل المستخدمين عبر الإنترنت بشكل متعاوني وتم تحميله بشكل مستقل، هذا الموقع لا يملك حقوق الملكية، لم يتم تعديل المحتوى بشكل يدوي، ولا يتحمل أي مسؤولية قانونية متعلقة بذلك. إذا كنت قد وجدت محتوى يشتبه في انتهاك حقوق النسخ، فلا تتردد في إرسال بريد إلكتروني إلى: notice#oldtoolbag.com (عند إرسال البريد الإلكتروني، يرجى استبدال # بـ @) لإبلاغنا، وقدم الدليل على ذلك، وإذا تم التحقق من ذلك، سيتم حذف المحتوى المشبوه فوراً.