เมื่อเร็ว ๆ นี้ฉันได้พัฒนาระบบและฉันมีข้อกำหนดในการดึงข้อมูลผ่านอีเมลของฉันหลังจากลืมรหัสผ่าน ทุกวันนี้ระบบจะบังคับให้อีเมลป้อนที่อยู่อีเมลเมื่อลงทะเบียน หนึ่งในวัตถุประสงค์คือการดึงข้อมูลผ่านการเชื่อมโยงอีเมลและคุณสามารถดึงรหัสผ่านได้ ฉันจะไม่พูดถึงฟังก์ชั่นการส่งอีเมลผ่าน Java แต่มุ่งเน้นไปที่การดึงรหัสผ่าน
อ้างถึงแนวคิดของคนอื่น: ส่งอีเมล→ขอ URL ในอีเมล→ตรวจสอบ URL → {ตรวจสอบการแก้ไขรหัสผ่านสำเร็จ แต่ข้ามไปยังหน้าล้มเหลวโดยไม่ประสบความสำเร็จ}
ประเด็นคือวิธีสร้าง URL นี้และวิธีการแยกวิเคราะห์ URL นี้
ควรสังเกตว่า URL สามารถแก้ไขรหัสผ่านได้เพียงครั้งเดียว เมื่อมีการส่งอีเมลหลายฉบับโดยบัญชีเดียวกันเฉพาะ URL ของอีเมลล่าสุดคือ
การเข้ารหัสสามารถป้องกันการโจมตีโดยการปลอมแปลง URL สามารถตรวจสอบได้เพียงครั้งเดียวและผูกมัดผู้ใช้ สร้าง URL: คุณสามารถใช้ UUID เพื่อสร้างคีย์แบบสุ่ม
Digital Signature = MD5 (ชื่อผู้ใช้ +'$' +เวลาหมดอายุ +'$' +คีย์คีย์)
ฟิลด์ฐานข้อมูล (ชื่อผู้ใช้ (คีย์หลัก), คีย์คีย์, เวลาหมดอายุ)
พารามิเตอร์ URL (ชื่อผู้ใช้, ลายเซ็นดิจิตอล), การสร้างคีย์: สร้างคีย์คีย์สำหรับผู้ใช้แต่ละคนเมื่อดึงรหัสผ่าน
ตัวอย่าง URL: http: // localhost: 8080/ผู้ใช้/reset_password?
สร้างเวลาหมดอายุสร้างลายเซ็นดิจิตอลสร้าง URL และส่งอีเมล SADORUPDATE (ชื่อผู้ใช้คีย์คีย์เวลาหมดอายุ)
ต่อไปนี้คือรหัส SpringMVC
@RequestMapping (value = "/user/i_forget_password") @ResponseBody แผนที่สาธารณะ ForgetPass (คำขอ httpservletRequest, ชื่อผู้ใช้สตริง) {users users = userservice.finduserByName (ชื่อผู้ใช้); MAP MAP = ใหม่ HashMap <String, String> (); สตริง msg = ""; ถ้า (users == null) {// ชื่อผู้ใช้ไม่มี msg = "ชื่อผู้ใช้ไม่มีอยู่คุณจะไม่ลืมชื่อผู้ใช้ใช่มั้ย"; map.put ("msg", msg); แผนที่กลับ; } ลอง {String SecretKey = UUID.RANDOMUUID (). TOSTRING (); // คีย์ไทม์สเตมเก่าล้าสมัย = การประทับเวลาใหม่ (System.currentTimeMillis ()+30*60*1000); // การหมดอายุหลังจากวันที่ยาว 30 นาที = outdate.getTime ()/1000*1000; // ละเว้นผู้ใช้มิลลิวินาที SetValidataCode (SecretKey); users.setRegisterDate (ล้าสมัย); userservice.update (ผู้ใช้); // บันทึกไปยังคีย์สตริงฐานข้อมูล = users.getUserName ()+"$"+วันที่+"$"+SecretKey; สตริง digitalsignature = md5.MD5ENCODE (คีย์); // สตริงลายเซ็นดิจิตอล emailtitle = "การดึงรหัสผ่านคลาวด์ Youfang"; String Path = request.getContextPath (); String basepath = request.getScheme ()+": //"+request.getServerName ()+":"+request.getServerport ()+path+"/"; String ResetPasshref = basepath+"ผู้ใช้/reset_password? sid ="+digitalsignature+"& username ="+users.getUserName (); string emailContent = "อย่าตอบกลับอีเมลนี้คลิกลิงก์ด้านล่างเพื่อรีเซ็ตรหัสผ่านของคุณ <br/> <a href ="+resetpasshref+"target = '_ blank'> คลิกฉันเพื่อรีเซ็ตรหัสผ่านของคุณ </a>"+"<br/> เคล็ดลับ: หากอีเมลนี้เกินกว่า 30 นาที System.out.print (ResetPasshref); sendmail.getInstatnce (). sendhtmlmail (emailtitle, emailcontent, users.getEmail ()); msg = "การดำเนินการสำเร็จและลิงก์การกู้คืนรหัสผ่านได้ถูกส่งไปยังที่อยู่อีเมลของคุณโปรดรีเซ็ตรหัสผ่านภายใน 30 นาที"; loginfo (คำขอชื่อผู้ใช้ "แอปพลิเคชันเพื่อดึงรหัสผ่านของคุณ"); } catch (exception e) {e.printstacktrace (); msg = "อีเมลไม่มีข้อผิดพลาดที่ไม่รู้จักโปรดติดต่อผู้ดูแลระบบ"; } map.put ("msg", msg); แผนที่กลับ; -ลิงค์ถูกส่งไปยังที่อยู่อีเมล ป้อนที่อยู่อีเมลและคลิกที่ลิงค์
ต่อไปนี้เป็นรหัสการยืนยันลิงก์ ตรวจสอบว่าโดยการข้ามไปยังอินเทอร์เฟซการปรับเปลี่ยนรหัสผ่านมิฉะนั้นกระโดดไปยังอินเตอร์เฟสที่ล้มเหลว
@RequestMapping (value = "/user/reset_password", method = requestMethod.get) public modelandView checkResetLink (สตริง SID, ชื่อผู้ใช้สตริง) {modelandView model = modelandView ใหม่ ("ข้อผิดพลาด"); สตริง msg = ""; if (sid.equals ("") || username.equals ("")) {msg = "ลิงก์ไม่สมบูรณ์โปรดสร้างใหม่"; model.addobject ("msg", msg); loginfo (ชื่อผู้ใช้ "ดึงลิงก์รหัสผ่านไม่ถูกต้อง"); โมเดลกลับ; } ผู้ใช้ users = userservice.finduserByName (ชื่อผู้ใช้); ถ้า (users == null) {msg = "ลิงก์ไม่ถูกต้องผู้ใช้ที่จับคู่ไม่สามารถพบได้โปรดใช้ใหม่เพื่อดึงรหัสผ่าน"; model.addobject ("msg", msg); loginfo (ชื่อผู้ใช้ "ลิงก์การกู้คืนรหัสผ่านไม่ถูกต้อง"); โมเดลกลับ; } timestamp outdate = users.getRegisterDate (); if (outdate.getTime () <= system.currentTimeMillis ()) {// หมายความว่ามันหมดอายุ msg = "ลิงก์หมดอายุโปรดใช้ใหม่เพื่อดึงรหัสผ่าน"; model.addobject ("msg", msg); loginfo (ชื่อผู้ใช้ "ดึงลิงก์รหัสผ่านไม่ถูกต้อง"); โมเดลกลับ; } string key = users.getUserName ()+"$"+outdate.getTime ()/1000*1000+"$"+users.getValidataCode (); // สตริงลายเซ็นดิจิตอล DigitalSignature = MD5.MD5ENCODE (คีย์); System.out.println (key+"/t"+digitalsignature); if (! digitalsignature.equals (sid)) {msg = "ลิงก์ไม่ถูกต้องมันหมดอายุหรือไม่? model.addobject ("msg", msg); loginfo (ชื่อผู้ใช้ "ลิงก์การกู้คืนรหัสผ่านไม่ถูกต้อง"); โมเดลกลับ; } model.setViewName ("user/reset_password"); // กลับไปที่อินเทอร์เฟซเพื่อแก้ไขโมเดลรหัสผ่าน AdDoBject ("ชื่อผู้ใช้" ชื่อผู้ใช้); โมเดลกลับ; -ภาคผนวก 1: ความแม่นยำของมิลลิวินาทีของวัตถุประเภทการประทับเวลาจะหายไปเมื่อบันทึกลงในข้อมูล ตัวอย่างเช่น: 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 ลงในตารางผู้ใช้โดยตรง มันจะโอเคที่จะเปรียบเทียบ SID โดยตรงเมื่อตรวจสอบ
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น