Vue+NodeJS+MongoDB实现邮箱验证注册、登录

一.主要内容

  • 邮件发送
  • 用户注册
  • 用户信息存储到数据库
  • 用户登录
  • 密码加密
  • JWT生成token
  • Cookie实现快速登录

在用户注册时,先发送邮件得到验证码.后端将验证进行缓存比对,如果验证码到期,比对不正确,拒绝登录;如果比对正确,将用户的信息进行加密存储到数据库.

用户登录时,先通过用户名去数据库查询是否存在该用户,如果不存在发送信息提示前端,如果存在.将用户输入的密码和将数据库中解密成功后的密码进行比对.如果成功,将用户的唯一id生成token与用户的信息一起发送给前端.前端将token存入Cookie中.

在一定时间内,用户第二次登录时.先去获取Cookie,将token解析出来,发送给后端,后端进行token解密,得到用户的id,通过id去数据库查询用户数据,并返回给前端.

二.MongoDB数据库配置及连接

1.配置

推荐看大佬写的

MongoDBicon-default.png?t=N7T8http://t.csdn.cn/f2yzh

版本推荐4以上,这里使用的是4.4.23

配置好后,我们创建一个数据库,为这个数据库添加一个用户.

db.createUser({user:"用户名", pwd: "用户密码", roles: [{role: "dbOwner", db: "数据库名"}]})

我们接下来连接这个数据库.

2.下载mongoose

npm i mongoose

3.database.js

const mongoose = require('mongoose'); 	const connect='mongodb://数据库用户名:数据库用户密码@127.0.0.1:27017/数据库名'
mongoose.connect(connect, {useNewUrlParser: true,useUnifiedTopology: true,
});
//创建实例
const db = mongoose.connection;
//数据库连接
db.on('error', console.error.bind(console, '连接错误:'));
db.once('open', function () {console.log('成功连接到数据库');
});//定义用户模型
...// 关闭连接(在程序退出时)
process.on('SIGINT', async function () {try {await mongoose.connection.close();console.log('数据库连接已关闭');process.exit(0);} catch (error) {console.error('关闭数据库连接时出错:', error);process.exit(1);}});module.exports = {db}

4.创建用户模型

用户信息包括

_id:数据库自动生成

username:用户名,唯一不可出现同样的用户名,

email:邮箱名,唯一不可出现同样的邮箱名,

password:密码,加密

...其他属性可以自定义添加

安装bcrypt,一种加密算法

npm i bcrypt
...连接// 定义用户模型
const userSchema = new mongoose.Schema({username:{type:String, unique:true}, //唯一,防止命名重复password:{type:String, set(val) //val是需要加密的值{return require('bcrypt').hashSync(val,10) //10加密强度}},  //加密email:{type:String,unique:true},});// 添加新的属性---如果后续有新的属性加入没有可以省略//userSchema.add({//  avatar_url: {type:String}//});//创建用户模型(集合)const User = mongoose.model('User', userSchema); ...关闭连接module.exports = {db,User}

至此数据库的配置连接就完成了

三.后端搭建

1.安装第三方包

npm install express --savenpm i body-parsernpm i cors

2.index.js

const express = require('express')
const  router = require('./router'); 		
const bodyParser = require('body-parser')		
const cors = require('cors');			
const app = express()app.use(cors()) //跨域处理
app.use(bodyParser.json())	 //解析请求体// 使用路由文件
app.use('/',router);app.listen(3000, () => {console.log('server running ...');
})

3.router.js

邮件发送我以及分离出来了,可以借鉴我的这篇博客.与这篇博客是对接上的.

Vue+NodeJS实现邮件发送icon-default.png?t=N7T8http://t.csdn.cn/OWAgl

 唯一要修改的地方就是,一个邮箱注册一个账号,你也可以自定义多少个

//发送邮件router.get('/getemail', async (req, res) => {try {const { mail } = req.query;// 验证邮箱是否存在const email = await User.findOne({ email: mail });if (email) {return res.status(422).json({ message: '邮箱存在账号' });}// 随机验证码// 将code存入缓存//发送邮件} catch (error) {});

安装jsonwebtoken

npm i jsonwebtoken

 一些数据密钥可以存储在一个.env文件中,可以参考这篇博客

Vue+NodeJS上传图片到腾讯云Cosicon-default.png?t=N7T8http://t.csdn.cn/cwN0N

const express = require('express');
const router = express.Router();
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const {User,db}=require('./database');	const SECRET=*******... //密钥,鉴权登录的时候来解析token//注册//登录//鉴权登录//邮件发送module.exports = router

3-1.注册

注册前,我们先发送邮件得到验证码,将验证码缓存.再请求注册接口的时候,先验证验证码的准确性.

如果错误或者过期了,不进行注册.


//用户注册
router.post('/register',async(req,res)=>{// 获取缓存---邮箱验证码let cachedValue = myCache.get("code");//解构出来前端传过来的信息let {code,username,password,email}=req.query.infoif(!cachedValue){return res.status(422).send({ message: '验证码过期' });}if(code!=cachedValue){return res.status(422).send({ message: '验证码输入错误' });}try {// 验证成功后,插入数据const user = await User.create({username: username,password: password,email: email,});myCache.del("code");//将用户信息发送给前端res.send(user);} catch (error) {console.error(error);res.status(422).send({message: '该用户已经存在'});}})

3-2.登录

这里我们是将用户的唯一_id生成token发给前端,前端将token存储到Cookie中,下次登录的时候将token发送给鉴权接口,读取token得到用户的_id.通过_id去查询数据库,得到用户的信息,实现登录.我们给Cookie设置时效性,在一定时间内,快速登录.

//用户登录
router.post('/login', async (req, res) => {try {let { username, password } = req.query.info;// 查询用户是否存在const user = await User.findOne({ username });// 用户名不存在if (!user) {return res.status(422).json({ message: '用户名不存在' });}// 校验密码//true或falseconst isPasswordValid = bcrypt.compareSync(password, user.password);if (!isPasswordValid) {return res.status(422).json({ message: '密码无效' });}// 生成 JWTconst token = jwt.sign({ id: String(user._id) }, SECRET); //密钥res.json({ //发送json数据user,token});} catch (error) {console.log(error)}})

3-3.鉴权登录

由于官方的规范,前端传过来的token格式是

所以将authorization切成两部分,取后面

//用户鉴权
router.get('/profile',async(req,res)=>{try {const rawToken = String(req.headers.authorization).split(' ').pop();const { id } = jwt.verify(rawToken, SECRET);const user = await User.findById(id);if (!user) {return res.status(404).json({ message: '用户不存在' });}res.json({user}); // 使用 .json() 方法发送 JSON 数据} catch (error) {console.log(error)}
})

至此我们的后端服务搭建完成

四.Vue前端

1.封装axios

这里我们将axios进行封装,多个请求时方便书写

1-1.http.js

import axios from "axios";const http = axios.create({baseURL: 'http://127.0.0.1:3000', // 注意这里的双斜杠timeout: 5000
});// 请求拦截器
http.interceptors.request.use(config => {return config;
}, error => {return Promise.reject(error);
});// 响应拦截器
http.interceptors.response.use(response => {return response.data;
}, error => {return Promise.reject(error);
});export default http;

1-2.api.js

import http from './http';//注册
export async function registerAPI(info) {const response = await http({url: 'register',method:'post',params: {info}});return response; // 返回响应数据}//登录
export async function loginAPI(info) {const response = await http({url: 'login',method:'post',params: {info}});return response; // 返回响应数据}//鉴权登录
export async function getTokenAPI(config) {const response = await http({url: 'profile',method:'get',// 自定义请求头headers:{authorization:config.authorization}});return response; // 返回响应数据}//邮箱

2.请求

我们先进行输入内容的去空格处理和为空的判断.

如果没有输入邮箱,不能发送邮件.

如果用户名,密码,邮箱,验证码有一项为空,不能注册.

2-1.发送邮件

...

2-2.注册

import {registerAPI} from './api'...// 注册function signUp(){
//去除空格
...
//判断是否为空
...let registerInfo={username:username.value,password:password.value,email:email.value,code:code.value}registerAPI(registerInfo).then(response => {console.log('Register successful:', response);}).catch(error => {// 处理错误console.log(error)});}

2-3.登录

在登录成功后,将token存储到Cookie中,设置存储时间.

import {loginAPI} from './api'
import useCookie from './Cookie';
const { setCookie } = useCookie();...//登录
function SignIn(){
//去除空格
username.value=username.value.replace(/\s/g, '')
password.value=password.value.replace(/\s/g, '')//判断是否为空
if(username.value==''||password.value==''){console.log('格式不正确')
}else{
const loginInfo={username:username.value,password:password.value}loginAPI(loginInfo).then(response => {setCookie('token', response.token, 0.5); // 存储30分钟console.log(response)}).catch(error => {// 处理错误console.log(error)});
}}

 

 

2-4.Cookie封装        


export default function useCookie() {//获取Cookieconst getCookie = (name) => {const value = `; ${document.cookie}`;const parts = value.split(`; ${name}=`);if (parts.length === 2) {return parts.pop().split(';').shift();}};//设置Cookieconst setCookie = (name, value, hours) => {const date = new Date();date.setTime(date.getTime() + (hours * 60 * 60 * 1000));const expires = `expires=${date.toUTCString()}`;document.cookie = `${name}=${value}; ${expires}; path=/`;};//销毁Cookieconst deleteCookie=(name)=>{// 将Cookie的过期时间设置为过去的日期document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;}return {getCookie,setCookie,deleteCookie};
}

 

2-5.鉴权登录

import {getTokenAPI} from './api'
import useCookie from './Cookie';
const { getCookie } = useCookie();...onMounted( async()=>{
// 读取Token
const Token = getCookie('token');
const config = {authorization: `Bearer ${Token}`, // 设置Bearer Token};// 发送需要Token的请求
await getTokenAPI(config).then(response => {// 处理响应数据console.log(response)}).catch(error => {// 处理错误console.log(error)});
})

至此前端页面完成.

如果有不对或者优化的地方欢迎指正,如果使用时出现了问题,可以留言评论,大家一起解决!

这里的token设置存在bug,没有真正的销毁token.有时间改正,有熟悉的大佬可以评论留言,给出好的解决办法.感谢!

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

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

相关文章

LRTimelapse 6 for Mac(延时摄影视频制作软件)

LRTimelapse 是一款适用于macOS 系统的延时摄影视频制作软件,可以帮助用户创建高质量的延时摄影视频。该软件提供了直观的界面和丰富的功能,支持多种时间轴摄影工具和文件格式,并具有高度的可定制性和扩展性。 LRTimelapse 的主要特点如下&am…

Leetcode刷题笔记--Hot41-50

1--二叉树的层序遍历(102) 主要思路: 经典广度优先搜索,基于队列; 对于本题需要将同一层的节点放在一个数组中,因此遍历的时候需要用一个变量 nums 来记录当前层的节点数,即 nums 等于队列元素的…

全网独家:编译CentOS6.10系统的openssl-1.1.1多版本并存的rpm安装包

CentOS6.10系统原生的openssl版本太老,1.0.1e,不能满足一些新版本应用软件的要求,但是它又被wget、mysql-libs、python-2.6.6、yum等一众系统包所依赖,不能再做升级。故需考虑在不影响系统原生openssl的情况下,安装较新…

HarmonyOS/OpenHarmony(Stage模型)应用开发单一手势(三)

五、旋转手势(RotationGesture) RotationGesture(value?:{fingers?:number; angle?:number}) 旋转手势用于触发旋转手势事件,触发旋转手势的最少手指数量为2指,最大为5指,最小改变度数为1度,拥有两个可…

mac安装adobe需要注意的tips(含win+mac all安装包)

M2芯片只能安装2022年以后的(包含2022年的) 1、必须操作的开启“任何来源” “任何来源“设置,这是为了系统安全性,苹果希望所有的软件都从商店或是能验证的官方下载,导致默认不允许从第三方下载应用程序。macOS sie…

力扣(LeetCode)算法_C++——寻找重复的子树

给你一棵二叉树的根节点 root ,返回所有 重复的子树 。 对于同一类的重复子树,你只需要返回其中任意 一棵 的根结点即可。 如果两棵树具有 相同的结构 和 相同的结点值 ,则认为二者是 重复 的。 示例 1: 输入:root…

智能合约安全分析,Vyper 重入锁漏洞全路径分析

智能合约安全分析,Vyper 重入锁漏洞全路径分析 事件背景 7 月 30 日 21:10 至 7 月 31 日 06:00 链上发生大规模攻击事件,导致多个 Curve 池的资金损失。漏洞的根源都是由于特定版本的 Vyper 中出现的重入锁故障。 攻击分析 通过对链上交易数据初步分…

Ubutnu允许ssh连接使用root与密码登录

文章目录 1. 修改sshd_config2. 设置root密码3. 重启SSH服务 1. 修改sshd_config 修改/etc/ssh/sshd_config文件,找到 #Authentication,将 PermitRootLogin 参数修改为 yes。如果 PermitRootLogin 参数被注释,请去掉首行的注释符号&#xff…

机器学习:基于梯度下降算法的逻辑回归实现和原理解析

这里写目录标题 什么是逻辑回归?Sigmoid函数逻辑回归损失函数梯度下降 逻辑回归定义逻辑函数线性组合模型训练决策边界 了解逻辑回归:从原理到实现什么是逻辑回归?逻辑回归的原理逻辑回归的实现逻辑回归的应用代码示例算法可视化 当涉及到二元…

01_TMS320F28004x系列MCU介绍和资料搜集

1. TI C2000 实时微控制器 TI公司在处理器方面的产品线有:基于ARM内核的微控制器/微处理器、MSP430微控制器、C2000系列实时微控制器、还有数字信号处理器(DSP)。 其中,C2000是TI公司专门针对实时控制推出的32位微控制器。TI公司…

SpingBoot整合Sa-Token框架(1)

一、文档参考:框架介绍 (sa-token.cc) 框架生态——开源项目 (sa-token.cc) 二、与SpingBoot整合 1、创建项目 在 IDE 中新建一个 SpringBoot 项目,例如:sa-token-demo-springboot(不会的同学请自行百度或者参考:Sp…

【系统设计系列】 DNS和CDN

系统设计系列初衷 System Design Primer: 英文文档 GitHub - donnemartin/system-design-primer: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards. 中文版: https://github.com/donnemarti…

『C语言进阶』指针进阶(一)

🔥博客主页: 小羊失眠啦 🔖系列专栏: C语言 🌥️每日语录:无论你怎么选,都难免会有遗憾。 ❤️感谢大家点赞👍收藏⭐评论✍️ 前言 在C语言初阶中,我们对指针有了一定的…

合宙Air724UG LuatOS-Air LVGL API控件-页面 (Page)

页面 (Page) 当控件内容过多,无法在屏幕内完整显示时,可让其在 页面 内显示。 示例代码 page lvgl.page_create(lvgl.scr_act(), nil) lvgl.obj_set_size(page, 150, 200) lvgl.obj_align(page, nil, lvgl.ALIGN_CENTER, 0, 0)label lvgl.label_crea…

【Spring Boot】SpringBoot 2.6.6 集成 SpringDoc 1.6.9 生成swagger接口文档

文章目录 前言一、SpringDoc是什么?二、使用步骤1.引入库2.配置类3.访问测试 总结其他配置立个Flag 前言 之前常用的SpringFox在2020年停止更新了,新项目集成SpringFox出来一堆问题,所以打算使用更活跃的SpringDoc,这里简单介绍一…

Nomad 系列-快速上手

系列文章 Nomad 系列文章 Nomad 重要术语 Nomad 安装设置相关术语 agent - 代理。Agent 是在 Server(服务器) 或 Client(客户端) 模式下运行的 Nomad 进程。client - 客户端。Nomad 客户端负责运行分配给它的任务。它还向服务器…

centos编译升级cmake,痛苦的Linux小白

环境 root 用户 下载 cmake官网下载地址:https://cmake.org/download/ 获取下载地址,右击cmake-3.27.4.tar.gz 命令行输入链接地址,下载 wget https://github.com/Kitware/CMake/releases/download/v3.27.4/cmake-3.27.4.tar.gz解压 tar -zx…

基于Pytest+Allure+Excel的接口自动化测试框架

1. Allure 简介 简介 Allure 框架是一个灵活的、轻量级的、支持多语言的测试报告工具,它不仅以 Web 的方式展示了简介的测试结果,而且允许参与开发过程的每个人可以从日常执行的测试中,最大限度地提取有用信息。 Allure 是由 Java 语言开发…

鼠标键盘管理 ShareMouse for Mac最新

软件“ShareMouse”允许您通过单个鼠标和键盘控制多台计算机: 将鼠标移动到您想要控制的计算机的监视器上,指针会神奇地跳转到该计算机。任何鼠标和键盘输入都会传输到相应的计算机。 与网络KVM类似,ShareMouse通过本地LAN传输鼠标移动和点…

【ARM AMBA5 CHI 入门 12 -- CHI 总线学习 】

文章目录 介绍CHI 特点Layers of the CHI architectureTopology Node TypeTransaction 分类Transaction 路由SAM 介绍Node ID 节点间数据怎么传输的呢? 介绍 CHI 的全称是 Coherent Hub Interface。所以从名字就能看出,CHI要解决什么问题了。按照惯例&a…