Java實(shí)現(xiàn)郵件找回密碼功能
本文實(shí)例為大家分享了Java實(shí)現(xiàn)郵件找回密碼功能的具體代碼,供大家參考,具體內(nèi)容如下
1、有個(gè)需求就是,忘記密碼后通過郵箱找回。現(xiàn)在的系統(tǒng)在注冊的時(shí)候都會強(qiáng)制輸入郵箱,其一目的就是 通過郵件綁定找回,可以進(jìn)行密碼找回。通過java發(fā)送郵件的功能我就不說了,重點(diǎn)講找回密碼。
2、參考別人的思路:發(fā)送郵件→請求郵件里的URL→驗(yàn)證url→{驗(yàn)證成功修改密碼,不成功跳轉(zhuǎn)到失敗頁面}
重點(diǎn)就是如何生成這個(gè)url和如何解析這個(gè)url.
需要注意的是一個(gè)url只能修改一次密碼,當(dāng)同一帳號發(fā)送多封郵件,只有最后一封郵件的url
3、加密能防止偽造攻擊,一次url只能驗(yàn)證一次,并且綁定了用戶。生成url: 可以用UUID生成隨機(jī)密鑰。
數(shù)字簽名 = MD5(用戶名+'$'+過期時(shí)間+‘$'+密鑰key)
數(shù)據(jù)庫字段(用戶名(主鍵),密鑰key,過期時(shí)間)
url參數(shù)(用戶名,數(shù)字簽名) ,密鑰key的生成:在每一個(gè)用戶找回密碼時(shí)候?yàn)檫@個(gè)用戶生成一個(gè)密鑰key ,url example: http://localhost:8080/user/reset_password?sid=D622D6A23FBF86FFE696B593D55351A54AEAEA77&userName=test4
生成過期時(shí)間,生成數(shù)字簽名,生成url,發(fā)送郵件.saveOrUpdate(用戶名,密鑰key,過期時(shí)間)
以下為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; //忽略毫秒數(shù) users.setValidataCode(secretKey); users.setRegisterDate(outDate); userService.update(users); //保存到數(shù)據(jù)庫 String key = users.getUserName()+"$"+date+"$"+secretKey; String digitalSignature = MD5.MD5Encode(key); //數(shù)字簽名 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 = "請勿回復(fù)本郵件.點(diǎn)擊下面的鏈接,重設(shè)密碼<br/><a href="+resetPassHref +" rel="external nofollow" target='_BLANK'>點(diǎn)擊我重新設(shè)置密碼</a>" + "<br/>tips:本郵件超過30分鐘,鏈接將會失效,需要重新申請'找回密碼'"+key+"\t"+digitalSignature; System.out.print(resetPassHref); SendMail.getInstatnce().sendHtmlMail(emailTitle,emailContent,users.getEmail()); msg = "操作成功,已經(jīng)發(fā)送找回密碼鏈接到您郵箱。請?jiān)?0分鐘內(nèi)重置密碼"; logInfo(request,userName,"申請找回密碼"); }catch (Exception e){ e.printStackTrace(); msg="郵箱不存在?未知錯(cuò)誤,聯(lián)系管理員吧。"; } map.put("msg",msg); return map; }
找回鏈接已經(jīng)發(fā)到郵箱了。進(jìn)入郵箱點(diǎn)開鏈接
以下為鏈接檢驗(yàn)代碼,驗(yàn)證通過 跳轉(zhuǎn)到修改密碼界面,否則跳轉(zhuǎn)到失敗界面
@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 = "鏈接錯(cuò)誤,無法找到匹配用戶,請重新申請找回密碼."; model.addObject("msg",msg) ; logInfo(userName,"找回密碼鏈接失效"); return model; } Timestamp outDate = users.getRegisterDate(); if(outDate.getTime() <= System.currentTimeMillis()){ //表示已經(jīng)過期 msg = "鏈接已經(jīng)過期,請重新申請找回密碼."; model.addObject("msg",msg) ; logInfo(userName,"找回密碼鏈接失效"); return model; } String key = users.getUserName()+"$"+outDate.getTime()/1000*1000+"$"+users.getValidataCode(); //數(shù)字簽名 String digitalSignature = MD5.MD5Encode(key); System.out.println(key+"\t"+digitalSignature); if(!digitalSignature.equals(sid)) { msg = "鏈接不正確,是否已經(jīng)過期了?重新申請吧"; model.addObject("msg",msg) ; logInfo(userName,"找回密碼鏈接失效"); return model; } model.setViewName("user/reset_password"); //返回到修改密碼的界面 model.addObject("userName",userName); return model; }
補(bǔ)充1:Timestamp類型對象在保存到數(shù)據(jù)的時(shí)候 毫秒精度會丟失。比如:2013-10-08 10:29:10.234 存到mysql數(shù)據(jù)庫的時(shí)候 變成 2013-10-08 10:29:10.0。時(shí)間變得不相同了,sid 匹配的時(shí)候不會相等。 所以我做了忽略精度的操作。
補(bǔ)充2:解決linux下面title中文亂碼
sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder(); mailMessage.setSubject(MimeUtility.encodeText(mailInfo.getSubject(), "UTF-8", "B")); //解決linux郵件title亂碼
補(bǔ)充3:怎么不直接把sid插入到user表呢。驗(yàn)證的時(shí)候直接比較sid就ok了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)日志文件監(jiān)聽并讀取相關(guān)數(shù)據(jù)的方法實(shí)踐
本文主要介紹了Java實(shí)現(xiàn)日志文件監(jiān)聽并讀取相關(guān)數(shù)據(jù)的方法實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Spring AOP定義AfterReturning增加實(shí)例分析
這篇文章主要介紹了Spring AOP定義AfterReturning增加,結(jié)合實(shí)例形式分析了Spring面相切面AOP定義AfterReturning增加相關(guān)操作技巧與使用注意事項(xiàng),需要的朋友可以參考下2020-01-01SpringBoot+Netty實(shí)現(xiàn)簡單聊天室的示例代碼
這篇文章主要介紹了如何利用SpringBoot Netty實(shí)現(xiàn)簡單聊天室,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)SpringBoot有一定幫助,感興趣的同學(xué)可以了解一下2022-02-02一行命令同時(shí)修改maven項(xiàng)目中多個(gè)module的版本號的方法
這篇文章主要介紹了一行命令同時(shí)修改maven項(xiàng)目中多個(gè)module的版本號的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-06-06SpringBoot集成echarts實(shí)現(xiàn)k線圖功能
ECharts是一款基于JavaScript的數(shù)據(jù)可視化圖表庫,提供直觀,生動,可交互,可個(gè)性化定制的數(shù)據(jù)可視化圖表,本文給大家介紹了SpringBoot集成echarts實(shí)現(xiàn)k線圖功能,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2024-07-07向Spring IOC 容器動態(tài)注冊bean實(shí)現(xiàn)方式
這篇文章主要為大家介紹了向Spring IOC 容器動態(tài)注冊bean實(shí)現(xiàn)方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07