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,"密码修改成功");
    }

 

posted @ 2022-05-23 17:04  Jimen  阅读(115)  评论(0)    收藏  举报