1. 程式人生 > 其它 >spring mvc 密碼找回功能

spring mvc 密碼找回功能

一、傳送郵件

Sprin提供了一個強大方便的郵件API,簡化了傳送郵件的工作,可以傳送富文字郵件,新增附件,使用模板渲染郵件內容。

1.  首先引入需要的jar包

<dependency>
  <groupId>javax.mail</groupId>
  <artifactId>mail</artifactId>
  <version>1.4.5</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>5.3.17</version>
</dependency>

2. 配置郵件傳送器

Spring郵件API的核心是MailSender介面,Spring自帶JavaMailSenderImpl實現了MailSender介面,所以需要將JavaMailSenderImpl裝配到Bean中。 mail.properties
#郵件傳送配置
#伺服器主機名 smtp.xx.com
mail.smtp.host=smtp.163.com
mail.smtp.port=25
mail.smtp.username=使用者名稱
#客戶端授權碼
mail.smtp.password=客戶端授權碼
#編碼字元
mail.smtp.defaultEncoding=utf-8
#是否進行使用者名稱密碼校驗
mail.smtp.auth= true
#設定超時時間
mail.smtp.timeout=20000

spring-context.xml 

<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    <property name="host" value="${mail.smtp.host}"/>
    <property name="port" value="${mail.smtp.port}"/>
    <property name="username" value="${mail.smtp.username}"/>
    <property name="password" value="${mail.smtp.password}"/>
    <property name="defaultEncoding" value="${mail.smtp.defaultEncoding}"/>
    <property name="javaMailProperties">
        <props>
            <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
            <prop key="mail.smtp.ssl.timeout">${mail.smtp.timeout}</prop>
            <prop key="mail.smtp.socketFactory.port">${mail.smtp.port}</prop>
            <prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
            <prop key="mail.smtp.ssl.trust">${mail.smtp.host}</prop>
            <prop key="mail.smtp.ssl.protocols">TLSv1.2</prop>
            <prop key="mail.smtp.starttls.enable">true
</prop> <prop key="mail.smtp.starttls.required">true</prop> <prop key="mail.smtp.port">${mail.smtp.port}</prop> <prop key="mail.debug">true</prop> </props> </property> </bean>

注意:需要在郵箱的設定中開啟SMTP服務

3. service層實現傳送郵件

@Override
    public boolean sendEmail(String recipient, String subject, String content) {
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        try {
            MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");

            /** 發件人的郵箱地址 */
            messageHelper.setFrom(emailFrom);
            /** 收件人郵箱地址 */
            messageHelper.setTo(recipient);
            /** 主題 */
            messageHelper.setSubject(subject);
            /** 內容
             * true代表支援html格式*/
            messageHelper.setText(content, true);
            mailSender.send(mimeMessage);
            return true;
        } catch (MessagingException e) {
            return false;
        }
    }

二、密碼找回

 1.  向用戶郵箱傳送重置密碼連結

生成一個30分鐘有效的令牌,將過期時間和令牌存入資料庫(也可以存到快取中)

public String forgotPassword(HttpServletRequest request,String email) throws CustomException {
        User user = userService.getUserByEmail(email);
        if(user == null){
            throw new CustomException("該郵箱未註冊");
        }
        try {
            String secretKey= UUID.randomUUID().toString();
            LocalDateTime outDate = LocalDateTime.now().plusMinutes(30);
            long date = outDate.toInstant(ZoneOffset.ofHours(8)).toEpochMilli()/1000*1000;
            String key = user.getName()+"$"+date+"$"+secretKey;
            String digitalSignature = new SimpleHash("MD5",key).toString();
            //儲存到資料庫
            user.setRegisterDate(outDate);
            user.setSid(digitalSignature);
            userService.update(user);
            String emailTitle = "密碼找回";
            String path = request.getContextPath();
            String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
            String resetPassHref =  basePath+"admin/user/reset_password?sid="+digitalSignature+"&email="+email;
            String emailContent = "請勿回覆本郵件.點選下面的連結,重設密碼<br/><a href="+resetPassHref +" target='_BLANK'>點選我重新設定密碼</a>" +
                    "<br/>tips:本郵件超過30分鐘,連結將會失效,需要重新申請'找回密碼'" +
                    "<br/>tips:本連結可能被郵箱攔截,如連結無效,請複製下列連結到您的瀏覽器中。<br/>"+
                    "連結開始:<span style='color:#F00; font-weight:bold'>"+resetPassHref+"<span>連結結束";
            System.out.print(resetPassHref);
            String msg = "操作成功,已經發送找回密碼連結到您郵箱。請在30分鐘內重置密碼";
//
            userService.sendEmail(email, emailTitle, emailContent);
            logger.info(msg);
            return "admin/forgot/sent";
        }catch (Exception e){
            throw new CustomException("未知錯誤,聯絡管理員吧。");
        }
    }

2.  點選郵件中的連結,進入校驗連結的方法

@RequestMapping(value = "/reset_password",method = RequestMethod.GET)
    public String resetPassword(HttpServletRequest request,String sid,String email) throws CustomException {
        String msg="";
        if(sid.equals("") || email.equals("")){
            msg="連結不完整,請重新生成";
            throw new CustomException(msg);
        }
        User user = userService.getUserByEmail(email);
        if(user == null){
            msg = "連結錯誤,無法找到匹配使用者,請重新申請找回密碼.";
            throw new CustomException(msg);
        }
        LocalDateTime outDate = user.getRegisterDate();
        //已經過期
        if(outDate.toInstant(ZoneOffset.ofHours(8)).toEpochMilli() <= System.currentTimeMillis()){
            msg = "連結已經過期,請重新申請找回密碼.";
            throw new CustomException(msg);
        }

        if(!user.getSid().equals(sid)) {
            msg = "連結不正確,是否已經過期了?重新申請吧";
            throw new CustomException(msg);
        }
        request.setAttribute("id",user.getId());
        return "admin/forgot/reset";
    }

3.  驗證通過後返回修改密碼的頁面,隱藏域中放userId

4.  提交修改密碼

@RequestMapping(value = "/reset_password",method = RequestMethod.POST)
    @ResponseBody
    public Result resetPassword(Long id,String new1,String new2) throws CustomException {
        if(!new1.equals(new2)){
            return PageResultUtil.error(500,"兩次輸入不一致");
        }
        userService.resetPassword(id,new1);
        return PageResultUtil.success(200,"密碼修改成功");
    }