使用邮箱验证实现登录功能(发送邮件,redis)

news2024/11/24 14:00:11

目录

概述 

前端搭建

 后端搭建

生成验证码-存入redis(主要过程代码)

发送邮件(主要过程代码)

登录验证-取出redis中数据进行验证(主要代码)

完整代码一-LoginController

完整代码二-LoginService

完整代码三-LoginInfo

功能测试


概述 

*使用邮箱进行登录验证功能实现。

主要功能点:

1.在SpringBoot环境中发送邮件。

2.使用redis进行验证码的缓存及取出验证登录

 整体过程说明 

前端搭建简易邮箱登录框,当验证通过后自动跳转到网页index.html。

后端提供两个接口,一个接口用于处理向指定邮箱发送验证码,并将验证码存入redis中,另一个接口用于处理登录验证,验证发来的邮箱地址和验证码是否匹配。

 技术选型 

前端:前端三剑客,axios 

后端:SpringBoot ,redis,javaMail

前端搭建

 项目结构 

 

 页面展示 

 说明 当我们输入邮箱地址后,点击"发送验证码",会判断输入是否为空以及输入的邮箱是否符合规范,如果输入不为空并且输入的邮箱符合规范,那么按钮将禁用并且提示再次发送的倒计时。

例如:

 

  前端完整代码实例 --- js

// 获取发送验证码按钮节点
let sendCodeBtn = document.querySelector("#sendCodeBtn");
// 获取邮箱地址输入框节点
let emailInput = document.querySelector("#userEmail");
// 获取验证码输入框节点
let verificationCode = document.querySelector("#CheckCode");
// 获取登录按钮节点
let loginBtn = document.querySelector("#loginBtn");

// 点击发送验证码逻辑代码
sendCodeBtn.addEventListener("click",function(){
    // 判断用户输入的邮箱地址是否符合规范
    let flag = CheckInputEmail(emailInput.value);
    // 以及判断输入是否为空
    if(emailInput.value && flag){
        // 调用方法发送请求,向目标邮箱发送验证码
        getCode(emailInput.value);
        alert("验证码发送成功!")
        // 禁用发送按钮
        sendCodeBtn.disabled = true;
        // 设置倒计时,时间到后才可以再次发起验证码请求
        let time = 60;
        sendCodeBtn.innerHTML =  time + "s后再次发送!"
        time--;
        let myInterVal =  setInterval(()=>{
            if(time != 0){
                sendCodeBtn.innerHTML = time + "s后再次发送!"
                time--;
            }else{
                sendCodeBtn.disabled = false;
                sendCodeBtn.innerHTML = "发送"
                clearInterval(myInterVal)
            }
        },1000)
    }else{
        alert("邮箱格式错误或为空!");
    }
})

// 点击登录按钮逻辑代码
loginBtn.addEventListener("click", function (){
    // 输入邮箱地址和验证码作为参数进行验证
    checkCode(emailInput.value,verificationCode.value);
})

// 验证邮箱输入格式是否正确
function CheckInputEmail(email){
    if (!email) {
        return false;
    }
    // 定义邮箱格式的正则表达式
    const emailRegex = /^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;

    // 检查邮箱是否符合格式要求
    return emailRegex.test(email);
}

// 发送请求:获取验证码
function getCode(emailAddress){
    axios.get("http://localhost:8080/logins?emailAddress="+emailAddress)
}

// 发送请求:检查验证码是否正确
function checkCode(emailAddress, code){
    axios.post("http://localhost:8080/logins",{
        emailAddress:emailAddress,
        code:code
    }).then(response =>{ // 成功的回调
        console.log("返回结果====>" + response.data)
        response.data? window.location = "../html/index.html" : alert("验证不通过!!!");
    })
}

 前端完整代码实例 --- html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <link rel="stylesheet" href="../css/login.css">
    <link href="../favicon.ico" rel="shortcut icon">
    <script src="../js/axios.min.js"></script>
</head>
<body>
<div id="container">
    <div id="my_header">
        <span id="header_title">邮箱登录</span>
    </div>
    <div id="my_body">
        <div id="body_inputBlock">
            <label for="userEmail">邮箱:</label><input id="userEmail" type="text" placeholder="请输入邮箱">
            <button id="sendCodeBtn" type="button">发送验证码</button><br><br>
            <label for="CheckCode">验证码:</label>
            <input id="CheckCode" type="password" placeholder="请输入验证码"><br>
            <button id="loginBtn">登录</button>
        </div>
    </div>
</div>
<script src="../js/login.js"></script>
</body>
</html>

  前端完整代码实例 --- css

#container{
    border: solid #589bff 2px;
    width: 500px;
    height: 250px;
    margin: 50px auto;
    border-radius: 5px;
    background-color: #7acc67;
}

#my_header{
    background-color: #bcffc1;
    height: 50px;
    line-height: 50px;
    text-align: center;
    font-weight: 800;
    font-size: 20px;
}

#my_body{
    margin-top: 15px;
    margin-left: 35px;
}

#loginBtn{
    font-weight: 800;
    font-size: 18px;
    margin-top: 20px;
    margin-left: 153px;
    width: 101px;
}

label{
    width: 104px;
    display: inline-block;
    text-align: right;
}
input{
    border-radius: 5px;
    height: 27px;
    width: 212px;
    background-color: antiquewhite;
}
label{
    font-size: 18px;
}

button{
    font-size: 15px;
    border-radius: 5px;
    background-color: antiquewhite;
    height: 36px;
}

button:hover{
    cursor: pointer;
}

#sendCodeBtn{
    position: relative;
    top: 1px;
    font-weight: 600;
}

 后端搭建

 目录结构 

生成验证码-存入redis(主要过程代码)

1.我们获取时间戳的后四位来模拟随机验证码。

// 截取当前时间戳的后四位模拟验证码
long timestamp = System.currentTimeMillis();
String verificationCode = Long.toString(timestamp).substring(Long.toString(timestamp).length() - 4);

2.有了随机的验证码,我们导入redis起步坐标,并简单配置连接信息。

<!--pom.xml导入redis起步坐标-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--application.yml中编写-->
redis:
  host: localhost <!--redis地址-->
  port: 6379 <!--redis开放端口号-->

3.使用-loginController中编写

/**
 * 注入redisTemplate用于缓存数据
 */
@Autowired
private RedisTemplate<String, String> redisTemplate;
// 将传入邮箱地址为key,验证码为value,存入redis中,并设置超时时间为5分钟
redisTemplate.opsForValue().set(emailAddress,verificationCode,1, TimeUnit.MINUTES);

发送邮件(主要过程代码)

1.获取授权码 

 说明 :我们想要在编程环境发送邮件,首先需要到我们自己所使用的邮箱中开启POP3/SMTP服务后获取授权密码。

 在此我使用的是网易的163邮箱,开启服务并获取授权密码步骤:

开启任意一个,根据步骤发送个短信后就出现授权码了。 

 

 2.编写邮件发送信息(需要授权码)

在application.yml中编写

 3.编写发送邮件方法-在loginService中编写邮件发送逻辑

// 自动注入JavaMailSender,用于发送邮件动作
@Autowired
private JavaMailSender javaMailSender;
 /**
 * 发送邮件
 * @param from 发送方
 * @param to 接收方
 * @param subject 主题
 * @param contents 内容
 * @return 返回执行结果状态
 */
public void sendEmail(String from, String to, String subject, String contents){
    // 创建一个简单消息对象,用于发送简单消息(不带附件或连接等)
    SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
    // 封装邮件信息
    simpleMailMessage.setFrom(from); // 设置发送方
    simpleMailMessage.setTo(to); // 设置接收方
    simpleMailMessage.setSubject(subject); // 设置主题
    simpleMailMessage.setText(contents); // 设置发送内容
    // 发送动作
    javaMailSender.send(simpleMailMessage);
}

4.调用方法-loginController中编写

/**
 * 注入loginService用于调用其中自定义的邮件发送方法
 */
@Autowired
private LoginService loginService;
// 编写邮件内容模板
String emailInfo = "验证码为:" + verificationCode +",5分钟内有效。";

// 发送验证码到目标邮箱
loginService.sendEmail("maohe101@163.com", emailAddress, "登录验证码", emailInfo);

登录验证-取出redis中数据进行验证(主要代码)

loginController中编写 

// 取出传入数据对比redis中数据,判断是否通过登录验证
// 判断传入的邮箱地址是否存在redis中
if(redisTemplate.hasKey(loginInfo.getEmailAddress())){
    // 取出对应邮箱地址为key的value值
    String storyCode = redisTemplate.opsForValue().get(loginInfo.getEmailAddress());
    // 判断存在redis中的验证码和传入验证码是否相同,相同返回true
    return loginInfo.getCode().equals(storyCode)? "true":"false";
}
return "false";

完整代码一-LoginController

package com.mh.controller;

import com.mh.pojo.LoginInfo;
import com.mh.service.LoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Date:2023/2/28
 * author:zmh
 * description: 登录页面相关接口
 **/
@Slf4j // 用于输出日志
@RestController
@RequestMapping("/logins")
public class LoginController {

    /**
     * 注入redisTemplate用于缓存数据
     */
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 注入loginService用于调用其中自定义的邮件发送方法
     */
    @Autowired
    private LoginService loginService;

    /**
     * 发送邮件
     * @param emailAddress 目标邮件地址,作为redis存储的key
     */
    @GetMapping
    public void sendEmail(String emailAddress){
        log.info("====>请求参数邮箱地址为{}",emailAddress);
        // 1.生成4位随机验证码
        // 截取当前时间戳的后四位模拟验证码
        long timestamp = System.currentTimeMillis();
        String verificationCode = Long.toString(timestamp).substring(Long.toString(timestamp).length() - 4);

        log.info("====>验证码为:{}",verificationCode);
        // 2.存入redis
        // 将传入邮箱地址为key,验证码为value,存入redis中,并设置超时时间为5分钟
        redisTemplate.opsForValue().set(emailAddress,verificationCode,1, TimeUnit.MINUTES);

        // 3.编写邮件内容模板
        String emailInfo = "验证码为:" + verificationCode +",5分钟内有效。";

        // 4.发送验证码到目标邮箱
        loginService.sendEmail("maohe101@163.com", emailAddress, "登录验证码", emailInfo);
    }

    /**
     * 登录验证
     * @param loginInfo 接收前端传入的邮箱地址和code
     * @return 返回执行结果
     */
    @PostMapping
    public String CheckEmailCode(@RequestBody LoginInfo loginInfo){
        log.info("=====>POST请求接收到的参数:{}***{}",loginInfo.getEmailAddress(), loginInfo.getCode());
        // 取出传入数据对比redis中数据,判断是否通过登录验证
        // 判断传入的邮箱地址是否存在redis中
        if(redisTemplate.hasKey(loginInfo.getEmailAddress())){
            // 取出对应邮箱地址为key的value值
            String storyCode = redisTemplate.opsForValue().get(loginInfo.getEmailAddress());
            // 判断存在redis中的验证码和传入验证码是否相同,相同返回true
            return loginInfo.getCode().equals(storyCode)? "true":"false";
        }
        return "false";
    }

}

完整代码二-LoginService

package com.mh.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

/**
 * Date:2023/2/28
 * author:zmh
 * description: 登录模块相关业务
 **/

@Service
public class LoginService {

    @Autowired
    private JavaMailSender javaMailSender;

    /**
     * 发送邮件
     * @param from 发送方
     * @param to 接收方
     * @param subject 主题
     * @param contents 内容
     * @return 返回执行结果状态
     */
    public void sendEmail(String from, String to, String subject, String contents){
        // 创建一个简单消息对象,用于发送简单消息(不带附件或连接等)
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        // 封装邮件信息
        simpleMailMessage.setFrom(from);
        simpleMailMessage.setTo(to);
        simpleMailMessage.setSubject(subject);
        simpleMailMessage.setText(contents);
        // 发送动作
        javaMailSender.send(simpleMailMessage);
    }

}

完整代码三-LoginInfo

package com.mh.pojo;

import lombok.Data;

/**
 * Date:2023/2/28
 * author:zmh
 * description: 登录信息-用于接收前端传入的body数据
 **/

@Data
public class LoginInfo {

    String emailAddress;
    String code;

}

功能测试

说明:在测试之前我们可以关闭一下浏览器缓存,方便我们测试。F12打开控制台

输入邮箱获取验证码

 邮箱接收到验证码

 输入错误验证码,进行对比验证

  输入正确验证码,进行对比验证 

 验证成功,自动跳转到index.heml网页,功能测试完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/377983.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

域基础和基本环境搭建

1.1 名词解释 域和工作组的区别&#xff1a; 工作组中所有的计算机都是对等的&#xff0c;也就是没有服务器和客户机的之分&#xff0c;所以工作组并不存在真正的集中管理作用&#xff1b;域是一个有安全边界的计算机集合&#xff0c;安全边界指的是一个域中的用户无法访问到另…

六、并发集合

文章目录并发集合ConcurrentHashMap存储结构存储操作put方法putVal方法-散列算法putVal方法-添加数据到数组&初始化数组putVal方法-添加数据到链表扩容操作treeifyBin方法触发扩容tryPreSize方法-针对putAll的初始化操作tryPreSize方法-计算扩容戳并且查看BUGtryPreSize方法…

[git可视化软件]gitkraken平替:GitAhead

日期2023-02-28 gitkraken6.5.1已经不能登陆使用了!! 6.5.1免费版已经无法使用!!! 现在是2023-02-28 这款工具已经废除了6.5.1版本的使用功能了,我直接卡在登陆界面进不去项目了. 要想继续管理私有项目,只能升级最新版的软件,并且开通会员.会员费用高的一批,一年要59.4美元.约…

前端进阶JS运行原理

JS运行原理 深入了解V8引擎原理 浏览器内核是由两部分组成的&#xff0c;以webkit为例&#xff1a; WebCore&#xff1a;负责HTML解析、布局、渲染等等相关的工作&#xff1b;JavaScriptCore&#xff1a;解析、执行JavaScript代码&#xff1b; 官方对V8引擎的定义&#xff1…

docker部署zabbix6.2.7+grafana

目录 1、下载docker 2、下载相关镜像文件 3、创建一个供zabbix系统使用的网络环境 4、创建一个供mysql数据库存放文件的目录 5、启动mysql容器 6、为zabbix-server创建一个持久卷 7、启动zabbix-server容器 8、创建语言存放目录 9、启动zabbix-web容器 10、启动zabbix…

探析集团企业 1+N 模式,重新定义集团型CRM

目录 一、客户经营、运营监控 二、流程驱动、业务成长 三、规则规范 业务治理 什么是集团型CRM【1N】&#xff1f;本文中我们可以把集团看作为“1”&#xff0c;其他分公司或组织看作为“N”。本篇我们主要分析集团CRM业务定位。 我们从企业集团总部的职能定位确定集团CRM…

攻不下dfs不参加比赛(七)

标题 为什么练dfs题目总结重点为什么练dfs 相信学过数据结构的朋友都知道dfs(深度优先搜索)是里面相当重要的一种搜索算法,可能直接说大家感受不到有条件的大家可以去看看一些算法比赛。这些比赛中每一届或多或少都会牵扯到dfs,可能提到dfs大家都知道但是我们为了避免眼高手…

数据结构(Java)---队列

1.简介 队列是一种操作受限的线性表&#xff0c;和栈类似&#xff0c;队列的限制主要是运行在表的一端进行插入操作&#xff0c;而在表的另一端进行删除的操作&#xff08;栈的操作受限是只能在一端进行插入和删除&#xff09;。队列中进行插入的一端称为队尾 &#xff0c;删除…

【JavaWeb】Servlet基础

文章目录1.Tomcat服务器安装注意事项2.编写WebApp3.BS系统角色和协议4.模拟Servlet4.1模拟sun公司4.2模拟Tomcat服务器4.3模拟WebApp开发者5.开发一个带有Servlet的WebApp5.1创建一个名为crm的项目5.2 在项目中创建一个名为WEB-INF的文件&#xff08;必须&#xff09;5.3在WEB-…

JAVA开发(java类加载过程)

1、java语言的平台无关性。 因为java语言可以跑在java虚拟机上&#xff0c;所以只要能装java虚拟机的地方就能跑java程序。java语言以后缀名 .java为文件扩展名。通过java编译器javac编译成字节码文件.class 。java字节码文件通过java虚拟机解析运行。所以java语言可以说是编译…

解决windows安装wxPython安装失败、速度过慢及PyCharm上wx包爆红问题

网上关于wxPython安装失败&#xff0c;安装速度过慢&#xff0c;以及安装成功后PyCharm中import wx仍然爆红的文章有很多&#xff0c;也特别杂&#xff0c;解决起来特别困难&#xff0c;今天在这里对问题的处理进行一个整合&#xff0c;希望能帮助到大家。 安装wxPython这里运用…

模拟微信聊天-课后程序(JAVA基础案例教程-黑马程序员编著-第八章-课后作业)

【案例9-1】 模拟微信聊天 【案例介绍】 1.案例描述 在如今&#xff0c;微信聊天已经人们生活中必不可少的重要组成部分&#xff0c;人们的交流很多都是通过微信来进行的。本案例要求&#xff1a;将多线程与UDP通信相关知识结合&#xff0c;模拟实现微信聊天小程序。通过监…

华为OD机试题【翻转单词顺序】用 C++ 进行编码 (2023.Q1)

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单) 文章目录 最近更新的博客使用说明翻转单词顺序题目输入输出示例一输入输出示例二输入输出说明示例三输入输出说明示例四

解决跑pytorch代码报错AttributeError: module ‘distutils‘ has no attribute ‘version‘

跑pytorch代码报错AttributeError: module ‘distutils’ has no attribute ‘version’ Traceback (most recent call last): File “D:/pycharm_envir/gaozhiyuan/Segmentation/pytorch_segmentation/deeplabv3-plus-pytorch-main/train.py”, line 16, in from utils.callb…

【C++修炼之路】22.哈希

每一个不曾起舞的日子都是对生命的辜负 哈希一.哈希概念及性质1.1 哈希概念1.2 哈希冲突1.3 哈希函数二.哈希冲突解决2.1 闭散列/开放定址法2.2 开散列/哈希桶三.开放定址法代码3.1 插入Insert3.2 查找Find3.3 删除Erase3.4 映射的改良&完整代码四.开散列代码4.1 插入Inser…

Linux之init.d、rc.d文件夹说明

备注&#xff1a;Ubuntu没有rc.d文件夹&#xff0c;原因看问题四 Linux的几个重要文件 rc.d&#xff0c;init.d文件夹的说明 今天在研究mysql的安装的时候&#xff0c;最后一步要创建一个软连接&#xff0c;使得mysql服务可以自启动&#xff0c;代码如下&#xff1a; ln -s…

扒系统CR8记录

目录 终极改造目标 过程记录 参考 为了将一套在线安装的系统&#xff0c;在不了解其架构、各模块细节的基础上&#xff0c;进行扒弄清楚&#xff0c;作以下记录。 终极改造目标 最终的目标&#xff0c;就是只通过CreMedia8_20230207.tar.gz解压 install 就把业务包安装了&…

CorelDRAW2023新功能有哪些?最新版cdr下载安装教程

使用 CorelDRAW2023&#xff0c;随时随都能进行设计创作。在 Windows或Mac上使用专为此平台设计的直观界面&#xff0c;以自己的风格尽情自由创作。同全球数百万信赖CorelDRAW Graphics Suite 的艺术家、设计者及小型企业主一样&#xff0c;大胆展现真我&#xff0c;创作出众的…

IAP初探

IAP(In-Application Programming)在应用编程&#xff0c;浅显易懂&#xff0c;按照字面意思即是在程序不关闭情况下&#xff0c;对应用进行再次写入程序&#xff0c;对程序的写入需要传输数据&#xff0c;而传输数据的前提是通信&#xff0c; IAP对代码进行更新可以简要分为以…

【ElasticSearch系列-01】初识以及安装elasticSearch

elasticSearch入门和安装一&#xff0c;elasticSearch入门1&#xff0c;什么是elasticSearch2&#xff0c;elasticSearch的底层优点2.1&#xff0c;全文检索2.2&#xff0c;倒排索引2.2.1&#xff0c;正排索引2.2.2&#xff0c;倒排索引2.2.3&#xff0c;倒排索引解决的问题2.2…