一.主要內(nèi)容
- 郵件發(fā)送
- 用戶注冊
- 用戶信息存儲到數(shù)據(jù)庫
- 用戶登錄
- 密碼加密
- JWT生成token
- Cookie實現(xiàn)快速登錄
在用戶注冊時,先發(fā)送郵件得到驗證碼.后端將驗證進行緩存比對,如果驗證碼到期,比對不正確,拒絕登錄;如果比對正確,將用戶的信息進行加密存儲到數(shù)據(jù)庫.
用戶登錄時,先通過用戶名去數(shù)據(jù)庫查詢是否存在該用戶,如果不存在發(fā)送信息提示前端,如果存在.將用戶輸入的密碼和將數(shù)據(jù)庫中解密成功后的密碼進行比對.如果成功,將用戶的唯一id生成token與用戶的信息一起發(fā)送給前端.前端將token存入Cookie中.
在一定時間內(nèi),用戶第二次登錄時.先去獲取Cookie,將token解析出來,發(fā)送給后端,后端進行token解密,得到用戶的id,通過id去數(shù)據(jù)庫查詢用戶數(shù)據(jù),并返回給前端.
二.MongoDB數(shù)據(jù)庫配置及連接
1.配置
推薦看大佬寫的
MongoDBhttp://t.csdn.cn/f2yzh
版本推薦4以上,這里使用的是4.4.23
配置好后,我們創(chuàng)建一個數(shù)據(jù)庫,為這個數(shù)據(jù)庫添加一個用戶.
db.createUser({user:"用戶名", pwd: "用戶密碼", roles: [{role: "dbOwner", db: "數(shù)據(jù)庫名"}]})
我們接下來連接這個數(shù)據(jù)庫.
2.下載mongoose
npm i mongoose
3.database.js
const mongoose = require('mongoose');
const connect='mongodb://數(shù)據(jù)庫用戶名:數(shù)據(jù)庫用戶密碼@127.0.0.1:27017/數(shù)據(jù)庫名'
mongoose.connect(connect, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
//創(chuàng)建實例
const db = mongoose.connection;
//數(shù)據(jù)庫連接
db.on('error', console.error.bind(console, '連接錯誤:'));
db.once('open', function () {
console.log('成功連接到數(shù)據(jù)庫');
});
//定義用戶模型
...
// 關(guān)閉連接(在程序退出時)
process.on('SIGINT', async function () {
try {
await mongoose.connection.close();
console.log('數(shù)據(jù)庫連接已關(guān)閉');
process.exit(0);
} catch (error) {
console.error('關(guān)閉數(shù)據(jù)庫連接時出錯:', error);
process.exit(1);
}
});
module.exports = {db}
4.創(chuàng)建用戶模型
用戶信息包括
_id:數(shù)據(jù)庫自動生成
username:用戶名,唯一不可出現(xiàn)同樣的用戶名,
email:郵箱名,唯一不可出現(xiàn)同樣的郵箱名,
password:密碼,加密
...其他屬性可以自定義添加
安裝bcrypt,一種加密算法
npm i bcrypt
...連接
// 定義用戶模型
const userSchema = new mongoose.Schema({
username:{type:String, unique:true}, //唯一,防止命名重復(fù)
password:{type:String, set(val) //val是需要加密的值
{
return require('bcrypt').hashSync(val,10) //10加密強度
}
}, //加密
email:{type:String,unique:true},
});
// 添加新的屬性---如果后續(xù)有新的屬性加入沒有可以省略
//userSchema.add({
// avatar_url: {type:String}
//});
//創(chuàng)建用戶模型(集合)
const User = mongoose.model('User', userSchema);
...關(guān)閉連接
module.exports = {db,User}
至此數(shù)據(jù)庫的配置連接就完成了
三.后端搭建
1.安裝第三方包
npm install express --save
npm i body-parser
npm 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
郵件發(fā)送我以及分離出來了,可以借鑒我的這篇博客.與這篇博客是對接上的.
Vue+NodeJS實現(xiàn)郵件發(fā)送http://t.csdn.cn/OWAgl
?唯一要修改的地方就是,一個郵箱注冊一個賬號,你也可以自定義多少個
//發(fā)送郵件
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存入緩存
//發(fā)送郵件
} catch (error) {
});
安裝jsonwebtoken
npm i jsonwebtoken
?一些數(shù)據(jù)密鑰可以存儲在一個.env文件中,可以參考這篇博客
Vue+NodeJS上傳圖片到騰訊云Coshttp://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=*******... //密鑰,鑒權(quán)登錄的時候來解析token
//注冊
//登錄
//鑒權(quán)登錄
//郵件發(fā)送
module.exports = router
3-1.注冊
注冊前,我們先發(fā)送郵件得到驗證碼,將驗證碼緩存.再請求注冊接口的時候,先驗證驗證碼的準確性.
如果錯誤或者過期了,不進行注冊.
//用戶注冊
router.post('/register',async(req,res)=>{
// 獲取緩存---郵箱驗證碼
let cachedValue = myCache.get("code");
//解構(gòu)出來前端傳過來的信息
let {code,username,password,email}=req.query.info
if(!cachedValue){
return res.status(422).send({ message: '驗證碼過期' });
}
if(code!=cachedValue){
return res.status(422).send({ message: '驗證碼輸入錯誤' });
}
try {
// 驗證成功后,插入數(shù)據(jù)
const user = await User.create({
username: username,
password: password,
email: email,
});
myCache.del("code");
//將用戶信息發(fā)送給前端
res.send(user);
} catch (error) {
console.error(error);
res.status(422).send({
message: '該用戶已經(jīng)存在'
});
}
})
3-2.登錄
這里我們是將用戶的唯一_id生成token發(fā)給前端,前端將token存儲到Cookie中,下次登錄的時候?qū)oken發(fā)送給鑒權(quán)接口,讀取token得到用戶的_id.通過_id去查詢數(shù)據(jù)庫,得到用戶的信息,實現(xiàn)登錄.我們給Cookie設(shè)置時效性,在一定時間內(nèi),快速登錄.
//用戶登錄
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或false
const isPasswordValid = bcrypt.compareSync(password, user.password);
if (!isPasswordValid) {
return res.status(422).json({ message: '密碼無效' });
}
// 生成 JWT
const token = jwt.sign({ id: String(user._id) }, SECRET); //密鑰
res.json({ //發(fā)送json數(shù)據(jù)
user,
token
});
} catch (error) {
console.log(error)
}
})
3-3.鑒權(quán)登錄
由于官方的規(guī)范,前端傳過來的token格式是
所以將authorization切成兩部分,取后面
//用戶鑒權(quán)
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() 方法發(fā)送 JSON 數(shù)據(jù)
} catch (error) {
console.log(error)
}
})
至此我們的后端服務(wù)搭建完成
四.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);
});
// 響應(yīng)攔截器
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; // 返回響應(yīng)數(shù)據(jù)
}
//登錄
export async function loginAPI(info) {
const response = await http({
url: 'login',
method:'post',
params: {info}
});
return response; // 返回響應(yīng)數(shù)據(jù)
}
//鑒權(quán)登錄
export async function getTokenAPI(config) {
const response = await http({
url: 'profile',
method:'get',
// 自定義請求頭
headers:{authorization:config.authorization}
});
return response; // 返回響應(yīng)數(shù)據(jù)
}
//郵箱
2.請求
我們先進行輸入內(nèi)容的去空格處理和為空的判斷.
如果沒有輸入郵箱,不能發(fā)送郵件.
如果用戶名,密碼,郵箱,驗證碼有一項為空,不能注冊.
2-1.發(fā)送郵件
...
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中,設(shè)置存儲時間.
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() {
//獲取Cookie
const getCookie = (name) => {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) {
return parts.pop().split(';').shift();
}
};
//設(shè)置Cookie
const 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=/`;
};
//銷毀Cookie
const deleteCookie=(name)=>{
// 將Cookie的過期時間設(shè)置為過去的日期
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
}
return {
getCookie,
setCookie,
deleteCookie
};
}
2-5.鑒權(quán)登錄
import {getTokenAPI} from './api'
import useCookie from './Cookie';
const { getCookie } = useCookie();
...
onMounted( async()=>{
// 讀取Token
const Token = getCookie('token');
const config = {
authorization: `Bearer ${Token}`, // 設(shè)置Bearer Token
};
// 發(fā)送需要Token的請求
await getTokenAPI(config)
.then(response => {
// 處理響應(yīng)數(shù)據(jù)
console.log(response)
})
.catch(error => {
// 處理錯誤
console.log(error)
});
})
至此前端頁面完成.
如果有不對或者優(yōu)化的地方歡迎指正,如果使用時出現(xiàn)了問題,可以留言評論,大家一起解決!文章來源:http://www.zghlxwxcb.cn/news/detail-697508.html
這里的token設(shè)置存在bug,沒有真正的銷毀token.有時間改正,有熟悉的大佬可以評論留言,給出好的解決辦法.感謝!文章來源地址http://www.zghlxwxcb.cn/news/detail-697508.html
到了這里,關(guān)于Vue+NodeJS+MongoDB實現(xiàn)郵箱驗證注冊、登錄的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!