项目优化方案之---实现邮箱用户登录

之前的项目中我写的基于SpringBoot和Vue的全栈项目已经实现了基本的用户接口开发,

不过其代码的功能单一,而且写的也是有不少漏洞(基本就像刚接手的代码*山一样)

那之后的几篇文章都来分享一下如何优化项目(每一章都独立讲方案,不必看之前的)

这里来添加一种登录方法,用邮箱来登录(实际思路跟手机号登录是差不多的,而且都是要借助一些第三方的工具实现)

操作之前先来梳理一下实现流程:

1.用户填写其邮箱(这里我只用QQ邮箱实现)

2.点击发送验证码按钮(ok,此处需要发送请求到后端进行一系列操作Todo)

3.获取到了验证码,填写验证码,并点击登录按钮(这里又要调用一次接口检验验证码是否正确)

总结一下后端要做的接口有哪些:

1.接收qq邮箱并生成验证码发送请求

       (具体实现:1.校验QQ邮箱是否格式正确(这里用SpringValildation即可),2.生成验证码,并将其保存到(??),这里其实有很多种方案可供选择,比如放到session,这里的话我用ThreadUtils操作一下,(后续统一用Redis操作),然后使用第三方工具把验证码发送到对应的QQ邮箱就可以了)

2.接收用户的验证码和其QQ邮箱号,进行二次校验,验证验证码与生成的验证码是否相等,如果相等就可以根据QQ邮箱去查找是否有这个人(这里可以拓展一下,如果没有这个人就可以直接帮他注册),这里没有这个人就返回没有这个用户并让其去注册的消息,如果有这个人就按照正常流程登录即可,(这里我的登录用的是JWT令牌,如果登录成功还要返回令牌给前端)

Ok,开始后端接口开发:

1.定义DTO

先确认一下之前定义的User实体类中要有email属性啊

    @Email
    @NotEmpty(message = "邮箱不能为空")
    private String email;

这里在User实体类这里记得要加上email邮箱属性(这里还有两个注释)

我这里用到了SpringValidation进行参数校验,(也就是这两个注解),不知道的同志可以看看之前的文章或者上网搜一下。

OK,这里就可以定义一个接收的实体类了,

由于两个接口一个接收QQ邮箱,一个接收QQ邮箱+验证码,因此这一个DTO也就足够了(如果愿意,也可以用User,不过我这个User定义的属性似乎有点多,感觉会很麻烦)

package org.example.cetidenet.model.dto.user;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;

public class UserEmailDTO {
    @Email
    @NotEmpty(message = "邮箱不能为空")
    private String email;
    
    private String code;

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public String toString() {
        return "UserEmailDTO{" +
                "email='" + email + '\'' +
                ", code='" + code + '\'' +
                '}';
    }
}

2.开发发送验证码的接口

在Controller类这里我们新定义一个方法

    @PostMapping("/submitEmail")
    public Result<User> submitEmail(@RequestBody @Validated UserEmailDTO userEmailDTO) {
        return userService.submitEmail(userEmailDTO);
    }

这里由于已经使用了@Validated来进行参数校验了,那我们直接返回userService的方法就好,尽量把逻辑处理的函数都放到Service的实现类中。

既然邮箱的格式已经正确了就生成一串随机数字吧

这里就使用RandomUtil生成

String code = RandomUtil.randomNumbers(6);

这样就生成了一个6位的随机数字;

既然万事俱备,那么就该发送验证码了,

3.讲解QQ邮箱发送验证码:
 

这里我使用JavaMail发送验证码,来看看使用方法:
 

步骤1.获取QQ邮箱授权码:

点开QQ邮箱,左上角有设置,点击设置

再点击账号

往下翻,点击开启服务即可

然后通过验证即可获取到授权码,(记得保存好)

步骤2:在后端工程中引入依赖
<dependency>
 <groupId>javax.mail</groupId>
 <artifactId>mail</artifactId>
 <version>1.4</version>
</dependency>
步骤3:按照代码填充:
import java.security.Security;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class MailClient {
  public static void main(String[] args) {
    try {
      final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";

      //配置邮箱信息
      Properties props = System.getProperties();
      //邮件服务器
      props.setProperty("mail.smtp.host", "smtp.qq.com");
      props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
      props.setProperty("mail.smtp.socketFactory.fallback", "false");
      //邮件服务器端口
      props.setProperty("mail.smtp.port", "465");
      props.setProperty("mail.smtp.socketFactory.port", "465");
      //鉴权信息
      props.setProperty("mail.smtp.auth", "true");
      //建立邮件会话
      Session session = Session.getDefaultInstance(props, new Authenticator() {
        //身份认证
        protected PasswordAuthentication getPasswordAuthentication() {
          //1.账户 授权码
          return new PasswordAuthentication("xxxxxxx@qq.com", "xxxx");
        }
      });
      //建立邮件对象
      MimeMessage message = new MimeMessage(session);
      //设置邮件的发件人
      message.setFrom(new InternetAddress("xxxxxxx@qq.com"));
      //2.设置邮件的收件人
      message.setRecipients(Message.RecipientType.TO, "xxxxxxx@qq.com");
      //设置邮件的主题
      message.setSubject("通过javamail发出!!!");
      //文本部分
      message.setContent("文本邮件测试", "text/html;charset=UTF-8");
      message.saveChanges();
      //发送邮件
      Transport.send(message);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

此处将          return new PasswordAuthentication("xxxxxxx@qq.com", "xxxx");

填充为你的账号和授权码,

下面的发件人填写你的邮箱(不要填别人的,不然要报错的)

收件人的邮箱填Controller类处接收到的代码即可;

下面来具体实现一下:

这个邮箱发送代码较长,这边可以将其封装为一个工具类或者函数(我感觉这种要长不长,要短不短的封装成函数比较合适)

那就来展示一下UserServiceImpl的这个方法调用吧;

@Override
    public Result<User> submitEmail(UserEmailDTO userEmailDTO) {
        String email = userEmailDTO.getEmail();
        String code = RandomUtil.randomNumbers(6);
        sendEmail(email,code);
        ThreadLocalUtil.set(code);
        return Result.success();
    }

    private static void sendEmail(String email,String code){

            try {
                final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";

                //配置邮箱信息
                Properties props = System.getProperties();
                //邮件服务器
                props.setProperty("mail.smtp.host", "smtp.qq.com");
                props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
                props.setProperty("mail.smtp.socketFactory.fallback", "false");
                //邮件服务器端口
                props.setProperty("mail.smtp.port", "465");
                props.setProperty("mail.smtp.socketFactory.port", "465");
                //鉴权信息
                props.setProperty("mail.smtp.auth", "true");
                //建立邮件会话
                Session session = Session.getDefaultInstance(props, new Authenticator() {
                    //身份认证
                    protected PasswordAuthentication getPasswordAuthentication() {
                        //1.账户 授权码
                        return new PasswordAuthentication("1147683258@qq.com", "bsfyppqvhrqqecgj");
                    }
                });
                //建立邮件对象
                MimeMessage message = new MimeMessage(session);
                //设置邮件的发件人
                message.setFrom(new InternetAddress("1147683258@qq.com"));
                //2.设置邮件的收件人
                message.setRecipients(Message.RecipientType.TO, email);
                //设置邮件的主题
                message.setSubject("来自Cetide网的信息");
                //文本部分
                message.setContent("收到您的登录请求发送验证码"+code, "text/html;charset=UTF-8");
                message.saveChanges();
                //发送邮件
                Transport.send(message);
            } catch (Exception e) {
                e.printStackTrace();
            }

    }

Ok,那么这个接口也就开发的差不多了,这里来验证一下吧,启动SpringBoot项目并打开Swagger试试

输入一个QQ小号的地址即可发送出验证码

那么,这也就发送成功了。(这里我测试的时候,感觉请求发出过程好慢,可以看看有没有更快速一些的QQ邮箱调用)

后续的登录就比较简单了,这里添加一个登录接口

这边也就不细致讲解了,直接上代码,大家观看吧

    @PostMapping("/email/submit")
    public Result login(@RequestBody @Validated UserEmailDTO userEmailDTO){
        // 实现登录功能
        return userService.emailLogin(userEmailDTO);
    }
    @Override
    public Result emailLogin(UserEmailDTO userEmailDTO) {
        String email = userEmailDTO.getEmail();
        String userCode = userEmailDTO.getCode();
        String code = ThreadLocalUtil.get();
        if(!code.equals(userCode)){
            return Result.error("验证码错误");
        }
        //现在说明这个验证码正确
        User user = userMapper.findByEmail(email);
        if(user == null){
            return Result.error("该邮箱未注册用户,请先注册");
        }
        //存在该用户
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", user.getId());
        claims.put("username", user.getUserName());
        String token = JwtUtil.genToken(claims);
        //存在且密码正确
        return Result.success(token);
    }
    @Select("select * from user where  email = #{email}")
    User findByEmail(String email);

此处代码也就差不多能够实现根据QQ邮箱登录的功能了;

相关推荐

  1. seleniumui自动化实例-邮箱登录

    2024-06-07 21:26:04       45 阅读
  2. Spring通过token获取登录用户信息的方式优化

    2024-06-07 21:26:04       32 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-07 21:26:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-07 21:26:04       101 阅读
  3. 在Django里面运行非项目文件

    2024-06-07 21:26:04       82 阅读
  4. Python语言-面向对象

    2024-06-07 21:26:04       91 阅读

热门阅读

  1. C# using的几个用途

    2024-06-07 21:26:04       27 阅读
  2. web学习笔记(六十四)

    2024-06-07 21:26:04       26 阅读
  3. 中介子方程四

    2024-06-07 21:26:04       25 阅读
  4. 深入探索Spark MLlib:大数据时代的机器学习利器

    2024-06-07 21:26:04       29 阅读
  5. 【leetcode--两数之和(输入有序数组)】

    2024-06-07 21:26:04       31 阅读
  6. 14.2 golint工具、godoc工具、Makefile文件

    2024-06-07 21:26:04       31 阅读
  7. Informer

    Informer

    2024-06-07 21:26:04      20 阅读
  8. 前后端交互:axios 和 json;springboot 和 vue

    2024-06-07 21:26:04       27 阅读