Recently, I have developed a system and I have a requirement to retrieve it through my email after forgetting my password. Nowadays, the system will force the email to enter the email address when registering. One of the purposes is to retrieve it through email binding and you can retrieve the password. I won’t talk about the function of sending emails through Java, but focus on retrieving passwords.
Refer to other people's ideas: Send emails → Request URLs in emails → Verify urls → {Verify successfully modify passwords, but jump to the failed page without success}
The point is how to generate this url and how to parse this url.
It should be noted that a url can only modify the password once. When multiple emails are sent by the same account, only the URL of the last email is
Encryption can prevent forgery attacks. The URL can only be verified once and binds the user. Generate url: You can use UUID to generate a random key.
Digital signature = MD5 (user name +'$'+expiration time +'$'+key key)
Database field (user name (primary key), key key, expiration time)
url parameters (user name, digital signature), key generation: generate a key key for each user when retrieving the password,
url example: http://localhost:8080/user/reset_password?sid=D622D6A23FBF86FFE696B593D55351A54AEAEA77&userName=test4
Generate expiration time, generate digital signature, generate url, and send email. saveOrUpdate (user name, key key, expiration time)
The following is springMvc code
@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){ //The user name does not exist msg = "The user name does not exist, you will not forget the user name, right?"; map.put("msg",msg); return map; } try{ String secretKey= UUID.randomUUID().toString(); //Key Timestamp outDate = new Timestamp(System.currentTimeMillis()+30*60*1000); //Expiration after 30 minutes long date = outDate.getTime()/1000*1000; //Ignore milliseconds users.setValidataCode(secretKey); users.setRegisterDate(outDate); userService.update(users); //Save to database String key = users.getUserName()+"$"+date+"$"+secretKey; String digitalSignature = MD5.MD5Encode(key); //Digital signature String emailTitle = "Youfang Cloud Password Retrieval"; 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 me to reset your password</a>" + "<br/>tips: If this email exceeds 30 minutes, the link will expire. You need to re-apply for 'retrieval password'"+key+"/t"+digitalSignature; System.out.print(resetPassHref); SendMail.getInstatnce().sendHtmlMail(emailTitle,emailContent,users.getEmail()); msg = "The operation was successful, and the password recovery link has been sent to your email address. Please reset your password within 30 minutes"; logInfo(request,userName,"Application to retrieve your password"); }catch (Exception e){ e.printStackTrace(); msg="The email does not exist? Unknown error, please contact the administrator. "; } map.put("msg",msg); return map; }The link has been sent to the email address. Enter the email address and click on the link
The following is the link verification code. Verify that by jumping to the password modification interface, otherwise jumping to the failed 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="The link is incomplete, please regenerate"; model.addObject("msg",msg) ; logInfo(userName,"Retrieve password link invalid"); return model; } Users users = userService.findUserByName(userName); if(users == null){ msg = "The link is wrong, the matching user cannot be found, please reapply to retrieve the password."; model.addObject("msg",msg) ; logInfo(userName,"The password recovery link is invalid"); return model; } Timestamp outDate = users.getRegisterDate(); if(outDate.getTime() <= System.currentTimeMillis()){ // means that it has expired msg = "The link has expired, please reapply to retrieve the password."; model.addObject("msg",msg) ; logInfo(userName,"Retrieve password link invalid"); 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 = "The link is incorrect, has it expired? Re-apply"; model.addObject("msg",msg) ; logInfo(userName,"The password recovery link is invalid"); return model; } model.setViewName("user/reset_password"); //Return to the interface for modifying password model.addObject("userName",userName); return model; }Supplement 1: The millisecond accuracy of Timestamp type objects will be lost when they are saved to data. For example: 2013-10-08 10:29:10.234 When stored in the mysql database, it becomes 2013-10-08 10:29:10.0. Times become different, and sid matches will not be equal. So I did an operation that ignored the accuracy.
Supplement 2: Solve Chinese garbled code in titles below linux
sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
mailMessage.setSubject(MimeUtility.encodeText(mailInfo.getSubject(), "UTF-8", "B")); //Solve linux mail title garbled
Supplement 3: Why don’t you insert sid into the user table directly? It would be OK to directly compare sid when verifying.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.