Skip to content

13.邮箱验证码发送实现

JustCoding-Hai edited this page Nov 8, 2020 · 1 revision

邮件发送实现

1.首先在自己的qq邮箱中开启POP3/SMTP服务.获取到授权码。相当于发送方的密码。 QQ邮箱登录页面地址 在这里插入图片描述 2.添加依赖包spring-boot-starter-mail

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

3.在appication.properties中配置邮件发送服务信息。

#SMTP服务器地址
spring.mail.host=smtp.qq.com
#SMTP服务器端口
spring.main.port=587
#发送者的用户名(邮箱)
spring.mail.username[email protected]
#发送方的授权码
spring.mail.password=#申请得到的授权码
#编码格式
spring.mail.default-encoding=UTF-8
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
#debug,输出邮件发送的过程
spring.mail.properties.mail.debug=true

4.测试发送简单的邮件

  //测试邮件发送
@Test
   void test03(){
    SimpleMailMessage msg=new SimpleMailMessage();
    //邮件的主题
    msg.setSubject("这是测试邮件主题");
    //邮件的内容
    msg.setText("这是测试邮件内容:\nsecond try");
    //邮件的发送方,对应配置文件中的spring.mail.username
    msg.setFrom("[email protected]");
    //邮件发送时间
    msg.setSentDate(new Date());
    //邮件接收方
    msg.setTo("[email protected]");
    //执行发送
    javaMailSender.send(msg);
}

5.登录邮箱验证码实现,管理端的登录页面获取验证码的接口代码如下:

/**
 * @author Hai
 * @date 2020/6/16 - 17:33
 */
@RestController
public class LoginController {
  /**
   * 获取验证码图片写到响应的输出流中,保存验证码到session
   * @param response
   * @param session
   * @throws IOException
   */
  @GetMapping("/verifyCode")
  public void getVerifyCode(HttpServletResponse response, HttpSession session) throws IOException {
    VerificationCode code = new VerificationCode();
    BufferedImage image = code.getImage();
    String text = code.getText();
    session.setAttribute("verify_code",text);
    VerificationCode.output(image,response.getOutputStream());
  }

  @Autowired
  JavaMailSender javaMailSender;
  /**
   * 获取邮箱验证码,并保存到本次会话
   * @param session
   */
  @GetMapping("/admin/mailVerifyCode")
  public RespBean getMailVerifyCode(HttpSession session){
    //获取随机的四个数字
    StringBuilder code=new StringBuilder();
    for (int i = 0; i <4; i++) {
      code.append(new Random().nextInt(10));
    }
   //邮件内容
    SimpleMailMessage msg = new SimpleMailMessage();
    msg.setSubject("微言聊天室管理端验证码验证");
    msg.setText("本次登录的验证码:"+code);
    msg.setFrom("[email protected]");
    msg.setSentDate(new Date());
    msg.setTo("[email protected]");
    //保存验证码到本次会话
    session.setAttribute("mail_verify_code",code.toString());
    //发送到邮箱
    try {
      javaMailSender.send(msg);
      return RespBean.ok("验证码已发送到邮箱,请注意查看!");
    }catch (Exception e){
      e.printStackTrace();
      return RespBean.error("服务器出错啦!请稍后重试!");
    }
  }
}

客户端界面发送“/admin/mailVerifyCode”请求,即发送随机的4位验证码到特定的邮箱中,并且把这四位验证码添加到当前请求会话(session)中。

6.配置Filter过滤器,拦截前端发来的登录管理端的请求,请判断请求中的参数“code”和会话中保存的“mail_verify_code”是否相等,相等就通过请求进行用户名和密码验证,否则直接返回。

/**
 * 拦截登录请求,验证输入的验证码是否正确
 * @author Hai
 * @date 2020/5/28 - 17:31
 */
@Component
public class VerificationCodeFilter extends GenericFilter {

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;
    //如果是登录请求则拦截
    if ("POST".equals(request.getMethod())&&"/doLogin".equals(request.getServletPath())){
      //用户输入的验证码
      String code = request.getParameter("code");
      //session中保存的验证码
      String verify_code = (String) request.getSession().getAttribute("verify_code");
      response.setContentType("application/json;charset=utf-8");
      PrintWriter writer = response.getWriter();
      //验证session中保存是否存在
      try {
        //验证是否相同
        if (!code.toLowerCase().equals(verify_code.toLowerCase())){
          //输出json
          writer.write(new ObjectMapper().writeValueAsString( RespBean.error("验证码错误!")));
          return;
        }else {
          filterChain.doFilter(request,response);
        }
      }catch (NullPointerException e){
        writer.write(new ObjectMapper().writeValueAsString(RespBean.error("请求异常,请重新请求!")));
      }finally {
        writer.flush();
        writer.close();
      }
    }
    //管理端登录请求
    else if ("POST".equals(request.getMethod())&&"/admin/doLogin".equals(request.getServletPath())){
      //获取输入的验证码
      String mailCode = request.getParameter("mailCode");
      //获取session中保存的验证码
      String verifyCode = ((String) request.getSession().getAttribute("mail_verify_code"));
      //构建响应输出流
      response.setContentType("application/json;charset=utf-8");
      PrintWriter printWriter =response.getWriter();
      try {
        if(!mailCode.equals(verifyCode)){
          printWriter.write(new ObjectMapper().writeValueAsString(RespBean.error("验证码错误!")));
        }else {
          filterChain.doFilter(request,response);
        }
      }catch (NullPointerException e){
         printWriter.write(new ObjectMapper().writeValueAsString(RespBean.error("请求异常,请重新请求!")));
      }finally {
       printWriter.flush();
       printWriter.close();
      }
    }
    else {
      filterChain.doFilter(request,response);
    }
  }
}

7.在Spring Security中的配置类MultiHttpSecurityConfig中通过以下代码,用于过滤每一次请求。

    //将验证码过滤器添加在用户名密码过滤器的前面
      http.addFilterBefore(verificationCodeFilter, UsernamePasswordAuthenticationFilter.class);
Clone this wiki locally