0.效果演示

插入视频插不进来,就很烦。可以出门右拐去优酷看下(点我!)。

1.后端搭建

1.1项目结构

首先看一下后端的server目录

挨个解释一下

  • 首先dbs文件夹顾名思义,操作数据库的,modules就是操作数据库的mongoose模型。
  • config.js是为了方便修改数据库数据。
  • interface就是接口文件夹,utils就是工具的意思呗,接口需要用到的axios和账号集权的passport都在这里修改(passport是啥待会儿再细说)。
  • 和utils同级的就是users.js 就是user接口的路由,具体的逻辑就在这个文件里
  • index.js和dbs,interface文件夹同级。是整个server目录的入口文件。

1.2后端配置

首先看一下config.js,直接放代码。

 // 导出相应的配置,然后可以方便的用下面的数据,改的话也比较方便修改。
export default {
//dbs 表示需要连接的服务器
dbs: "mongodb://127.0.0.1:27017/myblog2",
//redis对象是提供redis的信息
redis: {
get host() {
return "127.0.0.1";
},
get port() {
return 6379;
}
},
// smtp对象是利用邮箱来发送验证码的
smtp: {
get host() {
return "stmp.qq.com";
},
get user() {
return "470557449@qq.com";
},
// 这个pass码是qq邮箱给提供的。下面是随机打的不是真实的。
get pass() {
return "pfpeqwddadadasdaf";
},
// 制造一个随机的验证码
get code() {
return () => {
return Math.random()
.toString(16)
.slice(2, 6)
.toUpperCase();
};
},
// 创建一个时间,时间就是发送邮箱的时间。
get expire() {
return () => {
return new Date().getTime() + 60 * 60 * 1000;
};
}
}
};

针对于smtp协议,就是你可以利用它来发送验证码的。至于如何获取qq邮箱的pass码?

↓首先打开邮箱点击设置:

↓点击上方navbar的账号按钮

↓滑到下面,找到smtp选项

1.3创建数据模型

铺垫性的东西太多,建议都学完再来看。

1、mongodb和mongoose不详细展开讲了,mongodb可参考我之前写的入门教程(点我!

2、mongoose大体流程是引入,创建shcema ,创建model。然后进行操作。详情进入官网(点我!)。针对于这个顺序先不引入,引入是index.js里的,现在先讲创建schema和创建model这个部分的。

3、用了些async await和解构赋值的语法,如果有不太理解的可以自动跳转去学习一下新版本的js,推荐阮一峰的《ECMAScript 6 入门教程》(直接点书名!)

不多说,直接放代码:

 // server/dbs/modules/user.js
// 导入Monogoose
import mongoose from "mongoose";
// 创建schema
const Schema = mongoose.Schema;
// 创建userSchema
const UserSchema = new Schema({
username: {
type: String,
unique: true,
require: true
},
password: {
type: String,
require: true
},
email: {
type: String,
require: true
}
});
// 导出user模型
export default mongoose.model("User", UserSchema);

现在登录注册需要存入库中的只需要这些,验证方面的缓存数据统一存到redis里。reids的逻辑统一在users的接口里讲。

1.4创建users接口

可能大家没注意到我没说utils里的内容,axios和passport.js 。因为现在时机未到。

现在先配置一下user接口,支起来个架子,然后再谈逻辑

// koa-router必引的,不多解释
import Router from "koa-router";
// 发送验证码用redis,因为可能需求量会很大。redis效率较高
import Redis from "koa-redis";
// 用nodeMailer插件来发送邮件。
import nodeMailer from "nodemailer";
// USer模型,来操作mongodb
import User from "../dbs/modules/users";
// 用来发邮件的配置参数
import Email from "../dbs/config";
// axios来请求数据
import axios from "./utils/axios";
//来引入passprot中间件
import Passport from "./utils/passport"; // 创建一个路由,他的最开始用/users
let router = new Router({ prefix: "/users" }); // 创建一个redis的仓库。
let Store = new Redis().client; // 导出router
export default router;

redis的逻辑是引入koa-redis插件,然后新建store对象。然后我们针对store对象进行相应的操作。详细介绍请去npm看(点我!

1.4.1 注册验证码接口

首先第一个任务那就是注册,注册的逻辑是填写邮箱和用户名,确定密码,然后发送验证码邮件进行验证。

那么首先配置的就是发送验证码的路由,因为都是线性的代码,所以直接放代码,代码如下:

 1 // 发送验证码
2 router.post("/verify", async ctx => {
3 //获取username
4 let username = ctx.request.body.username;
5
6 //可以不看6-16行,看到结尾再回来看。
7 //获得验证码的有效时间
8 const saveExpire = await Store.hget(`nodemail:${username}`, "expire");
9 //如果验证码的有效时间太短,就不能再发次发送。
10 if (saveExpire && new Date().getTime() - saveExpire < 0) {
11 ctx.body = {
12 code: -1,
13 msg: "验证请求过于频繁,1分钟内1次"
14 };
15 return false;
16 }
17 //然后用nodeMailer创建一个transport
18 let transporter = nodeMailer.createTransport({
19 // server名称
20 service: "qq",
21 // user的名称和他的pass
22 auth: {
23 user: Email.smtp.user,
24 pass: Email.smtp.pass
25 }
26 });
27 //获取到验证码和时间,还有用户输入的邮箱和用户名
28 let ko = {
29 code: Email.smtp.code(),
30 expire: Email.smtp.expire(),
31 email: ctx.request.body.email,
32 user: ctx.request.body.username
33 };
34 // 邮件的配置文件
35 let mailOptions = {
36 from: `" 博客注册认证邮件" <${Email.smtp.user}>`,
37 to: ko.email,
38 subject: "王梓瑞的博客注册验证码",
39 html: `验证码是${ko.code},请尽快完成注册!`
40 };
41 await transporter.sendMail(mailOptions, (error, info) => {
42 if (error) {
43 return console.log(error);
44 } else {
45 // 当邮件发送成功了,就将数据保存起来,以后可以拿来用。
46 Store.hmset(
47 `nodemail:${ko.user}`,
48 "code",
49 ko.code,
50 "expire",
51 ko.expire,
52 "email",
53 ko.email
54 );
55 }
56 });
57 ctx.body = {
58 code: 0,
59 msg: "验证码已发送,可能会有延时,有效期1分钟"
60 };
61 });

1.4.2注册接口

等发完验证码 ,我们就可以继续进行注册操作。

同样直接放代码,很好理解。

router.post("/signup", async ctx => {
// 先获取表单里的信息,这么写是es6的解构赋值语法
const { username, password, email, code } = ctx.request.body;
if (code) {
const saveCode = Store.hget(`nodemail:${username}`, "code");
const saveExpire = Store.hget(`nodemail:${username}`, "expire"); if (saveCode == code) {
if (new Date().getTime() - saveExpire > 0) {
ctx.body = {
code: -1,
msg: "验证码已过期,请重新尝试"
};
return false;
}
} else {
ctx.body = {
code: -1,
msg: "请填写正确的验证码"
};
}
} else {
ctx.body = {
code: -1,
msg: "未输入验证码"
};
}
let user = await User.find({ username });
if (user.length) {
ctx.body = {
code: -1,
msg: "已被注册"
};
return;
}
let nuser = await User.create({ username, password, email });
console.log(nuser);
if (nuser) {
ctx.body = {
code: 0,
msg: "注册成功"
};
} else {
ctx.body = {
code: -1,
msg: "注册失败"
};
}
});

1.4.3 登录接口

进行到这里就涉及到了passport,因为登陆的状态是需要集中去进行管理的,那么就涉及到Passport这个插件。如果需要快速上手的话,可以看看这篇简书(点我!

我这里直接就是讲实战了。不多说了,可以参考着上面的简书加上我的代码自行理解。

 // server/interface/utils/passport.js
// 引入 passprot ,然后引入本地策略,就是验证用户是否成立,最后引入操作模型。
import passport from "koa-passport";
import LocalStrategy from "passport-local";
import UserModel from "../../dbs/modules/users"; // passport 加载策略中间件,然后通过新建location对象在里面进行对用户的鉴定。
passport.use(
//创建新的策略,然后三个参数分别是 用户名密码和回调
new LocalStrategy(async function(username, password, done) {
//此处用where是表示搜索的时候参数是一个对象
let where = {
username
};
// 用user的Mongoose的模型来搜索user在数据库中的记录,用res来接收
const res = await UserModel.findOne(where);
// 判断res是否存在, 不存在就用策略的回调函数done返回一个用户不存在的错误信息。
if (res != null) {
// 如果数据库里的Password和输入的password吻合,就返回一个res
if (res.password === password) {
return done(null, res);
} else {
// 不吻合就返回一个密码错误。
return done(null, false, "密码错误");
}
} else {
return done(null, false, "用户不存在");
}
})
); // 序列化和反序列化,没什么大事。
passport.serializeUser(function(user, done) {
done(null, user);
}); passport.deserializeUser(function(user, done) {
return done(null, user);
}); // 导出passport集权控制中间件。
export default passport;

再放user.js接口里的代码

 router.post("/signin", async (ctx, next) => {
return Passport.authenticate("local", (err, user, info, status) => {
if (err) {
ctx.body = {
code: -1,
msg: err
};
} else {
if (user) {
ctx.body = {
code: 0,
msg: "登录成功",
user
};
return ctx.login(user);
} else {
ctx.body = {
code: 1,
msg: info
};
}
}
})(ctx, next);
});

这里可能有人会有疑问,就说我的接口都没有获取到ctx里面的username和password数据,怎么直接就return了passport的对象呢?

问题就在必须在index.js让koa2对象使用bodyParser的中间件。代码如下:

 // bodyParser中的extendTypes必须要加,要不然passport就无法解析username和passport
app.use(
bodyParser({
extendTypes: ["json", "form", "text"]
})
);

然后就可以解析到登录过来的username和passport了。

1.4.4 退出和查询用户接口

直接放代码,没有难度

 router.get("/getUser", async ctx => {
if (ctx.isAuthenticated()) {
const { username, email } = ctx.session.passport.user;
ctx.body = {
user: username,
email
};
} else {
ctx.body = {
user: "",
email: ""
};
}
});

退出登录

 router.get("/exit", async (ctx, next) => {
await ctx.logout();
if (!ctx.isAuthenticated()) {
ctx.body = {
code: 0
};
} else {
ctx.body = {
code: -1
};
}
});

如果你想获取用户数据的话还有第二种方法,从session获取,session是什么?大家自行百度下,简单来说就是服务端的cookie。

然后运用vuex 配合 nuxt.js的nuxtServerInit方法。这个又需要理解vuex和nuxtServerInit,这个放上链接,vuexnuxtServerInit

项目结构

如果用vue-cli会有modules文件夹来放模型的,但是nuxt.js直接都放在平级了,详情可参照nuxt.js文档。(点我!)

同样直接放代码吧。

 //store/user.js
const state = () => ({
user: ""
});
const mutations = {
setUser(state, param) {
state.user = param;
}
};
const actions = {
setUser: ({ commit }, param) => {
commit("setUser", param);
}
}; export default { state, mutations, actions };
 //store/index.js
const actions = {
async nuxtServerInit({ commit }, { req }) {
if (req.user) {
commit("user/setUser", req.user.username);
}
}
}; export { actions };

然后我们就可以在页面的任何位置调用 $store.state.user.user 即可获得用户的用户名了。可以省去异步获取的操作。

1.5 index.js文件

直接放代码,之前解释的都解释过了,这个就是一个启动后端的文件

 // server/index.js
const Koa = require("koa");
const consola = require("consola");
const { Nuxt, Builder } = require("nuxt"); import bodyParser from "koa-bodyparser"; // 这个一开始就要加,不加的话解析不出来request.body。post请求就白给。
import json from "koa-json";
import mongoose from "mongoose";
import dbConfig from "./dbs/config";
import Redis from "koa-redis";
import session from "koa-generic-session";
import users from "./interface/users";
import passport from "./interface/utils/passport"; const app = new Koa(); // Import and Set Nuxt.js options
const config = require("../nuxt.config.js");
config.dev = app.env !== "production"; async function start() {
// Instantiate nuxt.js
const nuxt = new Nuxt(config); const {
host = process.env.HOST || "127.0.0.1",
port = process.env.PORT || 3000
} = nuxt.options.server; //这个是加密用的
app.keys = ["my", "keyskeys"];
//是否设置代理
app.proxy = true;
//session的前缀
app.use(session({ key: "my", prefix: "my:uid", store: new Redis() }));
//mongoose链接Mongodb
mongoose.connect(dbConfig.dbs, {
useNewUrlParser: true
});
//初始化passport
app.use(passport.initialize());
//让passport使用session
app.use(passport.session()); // Build in development
if (config.dev) {
const builder = new Builder(nuxt);
await builder.build();
} else {
await nuxt.ready();
}
//解析json用的中间件
app.use(json());
// bodyParser中的extendTypes必须要加,要不然passport就无法解析username和passport
app.use(
bodyParser({
extendTypes: ["json", "form", "text"]
})
);
// 加载路由中间件
app.use(users.routes()).use(users.allowedMethods()); app.use(ctx => {
ctx.status = 200;
ctx.respond = false; // Bypass Koa's built-in response handling
ctx.req.ctx = ctx; // This might be useful later on, e.g. in nuxtServerInit or with nuxt-stash
nuxt.render(ctx.req, ctx.res);
}); app.listen(port, host);
consola.ready({
message: `Server listening on http://${host}:${port}`,
badge: true
});
} start();

vue koa2 mongodb 从零开始做个人博客(二) 登录注册功能后端部分的更多相关文章

  1. vue koa2 mongodb 从零开始做个人博客(一) 登录注册功能前端部分

    0.效果演示 插入视频插不进来,就很烦.可以出门右拐去优酷看下(点我!). 1.准备工作 1.1前端框架 前端使用了基于vue.js的nuxt.js.为什么使用nuxt.js? 首先我做的是博客的项目 ...

  2. 一个基于Vue.js+Mongodb+Node.js的博客内容管理系统

    这个项目最初其实是fork别人的项目.当初想接触下mongodb数据库,找个例子学习下,后来改着改着就面目全非了.后台和数据库重构,前端增加了登录注册功能,仅保留了博客设置页面,但是也优化了. 一.功 ...

  3. Flask博客类登录注册验证模块代码(十四)

    1 文件系统 blog #博客类 App forms #表单 __init__.py user.py models #模型 __init__.py user.py static #静态文件 templ ...

  4. NodeJS+Mongodb+Express做CMS博客系统

    楼主正在用业余时间开发中-- ,目前的版本仅支持会员系统,尝鲜一下吧~ hi-blog 一个 nodejs+express+mongodb 的 cms 系统 怎么启动 默认你已经安装了 mongodb ...

  5. 基于 Hexo 从零开始搭建个人博客(二)

    阅读本篇前,请先配置好相应的环境,请仔细阅读教程 基于 Hexo 从零开始搭建个人博客(一). 原文链接:基于 Hexo 从零开始搭建个人博客(二) 前言 博客搭建过程遇到任何问题,优先在本页面搜索, ...

  6. 从零开始,搭建博客系统MVC5+EF6搭建框架(4)下,前后台布局实现、发布博客以及展示。

    一.博客系统进度回顾 目前已经完成了,前台展示,以及后台发布的功能,最近都在做这个,其实我在国庆的时候就可以弄完的,但是每天自己弄,突然最后国庆2天,连电脑都不想碰,所以就一直拖着,上一篇写了前端实现 ...

  7. 基于react全家桶+antd-design+webpack2+node+express+mongodb开发的前后台博客系统

    很久没更新博客,最近也有点忙,然后业余时间搞了一个比较完整基于react全家桶+antd-design+webpack2+node+express+mongodb开发的前后台博客系统的流程系统,希望对 ...

  8. nodejs实战《一起学 Node.js》 使用 Express + MongoDB 搭建多人博客

    GitHub: https://github.com/nswbmw/N-blog N-blog 使用 Express + MongoDB 搭建多人博客 开发环境 Node.js: 6.9.1 Mong ...

  9. 基于 Hexo 从零开始搭建个人博客(五)

    阅读本篇前,请先阅读前几篇文章: 基于 Hexo 从零开始搭建个人博客(一) 基于 Hexo 从零开始搭建个人博客(二) 基于 Hexo 从零开始搭建个人博客(三) 基于 Hexo 从零开始搭建个人博 ...

随机推荐

  1. Pyinstaller打包exe,丢失图标等问题

    Pyinstaller打包exe,丢失图标等问题 一.原因 exe运行时会解压一个名为'_MEI*'的资源文件夹到电脑的临时目录,程序结束时删除. 程序里使用'\图标.png'这样的路径,exe运行时 ...

  2. 一招教你轻松使用数据可视化BI软件创建旅游消费数据可视化大屏

    灯果数据可视化BI软件是新一代人工智能数据可视化大屏软件,内置丰富的大屏模板,可视化编辑操作,无需任何经验就可以创建属于你自己的大屏.大家可以在他们的官网下载软件.   本文以旅游消费数据可视化大屏为 ...

  3. 编译Qualcomm的Hexagon exampls错误

    在下载了Qualcomm的Hexagon SDK 351版本之后,想跑里面的examples,然后参照文档的说,比如在examples/common/sobel3x3_v60目录下面,先执行了SDK根 ...

  4. Android中实现照片滑动时左右进出的动画的xml代码

    场景 Android中通过ImageSwitcher实现相册滑动查看照片功能(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/det ...

  5. linux中shell内置命令和外置命令

    shell内置命令 无法通过which或者whereis去查找命令的位置 例如cd,cp这些命令是shell解释器内置的命令 当shell内置命令传入shell解释器,shell解释器通过内核获取相关 ...

  6. PMP--1.7 项目治理

    治理凌驾于管理之上 组织治理用于影响项目治理. 组织治理需要组织根据组织文化.项目类型和组织需求裁剪治理框架,适用于当前组织. 其实组织治理的内容,在项目管理初期不需要详细了解,组织治理的内容都是高层 ...

  7. Java软件工程师技能图谱

    原文链接:Java软件工程师技能图谱 最近在考虑"拥有怎样的技能才能算一名合格的java软件工程师呢?"这个问题.碰巧在github发现一个很棒的开源项目--程序员技能图谱.@Zh ...

  8. 简单的OO ALV显示ALV及下载

    REPORT OO_ALV. CLASS OO_ALV DEFINITION. PUBLIC SECTION. METHODS:GET_DATA IMPORTING AMOUNT TYPE I,&qu ...

  9. java面试必问问题总结

    1. 自我介绍 2. get跟load的区别 3. 什么是重载,什么是重写 4. HashTable跟HashMap的区别 5. Jsp九大隐式对象 6. Forword和redirect 的区别 7 ...

  10. Apache Avro总结

    参考 Apache Avro™ 1.9.0 Specification Avro介绍 小而巧的数字压缩算法:zigzag   原始类型(Primitive Types) 类型名 描述 描述 二进制编码 ...