文章简介
在上一篇中,我们以用户注册为例,详细介绍了一个 API 接口的完整开发流程,并将数据库引入项目中来,本篇中将继续完善用户登录及登出的逻辑。
第一步 前端事件注册
在 public/main/js/index.js
中添加登录按钮点击时的事件回调:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
$(function () { // ... 注册逻辑已省略 // 登录 $('.login .logBtn').click(function () { $.ajax({ type: 'post', url: '/api/user/login', data: { username: $('.login input[name="username"]').val(), password: $('.login input[name="password"]').val(), }, dataType: 'json', success: function (res) { console.log(res) } }) }) }) |
第二步 在后台路由中注册登录方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
在/routers/api中添加方法,处理登录的逻辑 router.post('/user/login', function (req, res, next) { let username = req.body.username let password = req.body.password if (username === '' || password === '') { resData.code = 1 resData.message = '用户名或密码不能为空' res.json(resData) return } // 查询数据库中对应的用户名和密码的记录 User.findOne({ username: username, password: password }).then(function(userInfo) { if (!userInfo) { resData.code = 2 resData.message = '用户名或密码错误' res.json(resData) return } resData.message = '登录成功' resData.userInfo = { _id: userInfo._id, username: userInfo.username } res.json(resData) }) }) |
第三步 使用 Cookie 记录用户登录状态
在入口文件中需要引入并初始化 Cookies 模块:
1 2 3 4 5 6 7 8 9 |
// 加载cookie模块 var cookies = require('cookies') // 设置cookies app.use(function (req, res, next) { req.cookies = new Cookies(req, res); next(); }) |
接下来,就可以通过 get 或 set 方法来获取或设置 Cookie。
在用户登录成功后的响应信息中,将 Cookie 信息返回给客户端,之后客户端再向服务器发起请求时将会带着该信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
if (!userInfo) { resData.code = 2 resData.message = '用户名或密码错误' res.json(resData) return } resData.message = '登录成功' resData.userInfo = { _id: userInfo._id, username: userInfo.username } req.cookies.set('userInfo', JSON.stringify(userInfo)) res.json(resData) |
用户再次访问时就会将 Cookie 带过来,我们在入口文件处就可以得到该 Cookie:
1 2 3 4 5 6 |
app.use(function (req, res, next) { req.cookies = new Cookies(req, res); console.log(req.cookies.get('userInfo')) next(); }) |
以下是浏览器客户端发过来的请求的请求头中 Cookie 的信息,我们可以看到:
1 2 |
Cookie: _ga=GA1.1.1825883494.1540870369; userInfo={"_id":"5c1f932a9370e653943ebb66","username":"myj","password":"123","__v":0} |
接下来,我们需要将该 Cookie 信息保存在 request 对象中,这样一来在其他地方也能引用到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 设置cookies app.use(function (req, res, next) { let userInfo = req.cookies.get('userInfo') req.cookies = new Cookies(req, res) console.log('用户cookie信息', userInfo) try { req.userInfo = JSON.parse(userInfo) } catch (e) { req.userInfo = {} } next(); }) |
第四步 引入模板,在前端展示用户登录状态
为了使得登录成功后即使是刷新页面,依然能够保留登录信息,我们需要引入模板引擎,将首页 index.html 作为一个动态模板,将用户信息作为变量传入模板中:
1 2 3 4 5 6 7 8 9 10 11 12 |
var express = require('express') var router = express.Router() router.get('/', function (req, res, next) { // 第二个参数就是用户信息变量 res.render('main/index', { userInfo: req.userInfo }) }) module.exports = router |
接下来,就可以在模板中判断是否传来了UserInfo信息,进而确定模板的渲染:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{% if userInfo._id %} <div class="user-info"> <div class="username-wrap">您好,<span class="username">{{userInfo.username}}</span></div> <span class="logout">退出</span> </div> {% else %} <form class="register"> <input type="text" name="username" /> <input type="password" name="password" /> <input type="button" class="regBtn" value="注册" /> </form> <form class="login"> <input type="text" name="username" /> <input type="password" name="password" /> <input type="button" class="logBtn" value="登录" /> </form> {% endif %} |
第五步 退出登录
退出登录时需要将 Cookie 清空。
前端绑定事件:
1 2 3 4 5 6 7 8 9 10 |
$('.user-info .logout').click(function () { $.ajax({ type: 'post', url: '/api/user/logout', success: function (res) { regAndLogSucc(res) } }) }) |
后台封装方法:
1 2 3 4 5 6 |
router.post('/user/logout', function (req, res, next) { req.cookies.set('userInfo', {}) resData.message = '退出成功' res.json(resData) }) |
第六步 区分管理员和普通用户
截止到目前为止,我们只有普通用户这一种角色,在博客系统的后端,管理员可以看到所有用户的信息,而管理员本身也可以有普通用户的一系列操作权限,因此我们需要添加管理员这一角色,可以在 Schema 数据库表描述文件中添加 isAdmin 字段。
默认情况下,用户类型为普通用户,因此 isAdmin 的默认值为 false。
/schemas/users.js
1 2 3 4 5 6 7 8 9 |
module.exports = new Schema({ username: String, password: String, isAdmin: { type: Boolean, default: false } }) |
手动在 Mongo 库中插入一条记录,添加管理员账号:
1 2 |
db.users.insert({"username":"admin","password":"admin","isAdmin":true}); |
插入后执行查询测试一下是否成功:
1 2 |
db.users.find(); |
如果结果为:
1 2 3 |
{ "_id" : ObjectId("5c1f932a9370e653943ebb66"), "username" : "myj", "password" : "123", "__v" : 0 } { "_id" : ObjectId("5c6242d77b9f0cb589211b0a"), "username" : "admin", "password" : "admin", "isAdmin" : true } |
则插入成功。
在登录之后,在 app.js 入口文件中对 Cookies 的处理过程中,得到用户名之后,就可以查询该用户是否为管理员,并将这一信息缓存到 req 对象上,供后续的逻辑使用,出于逻辑处理方便的考虑,我们不把用户是否为管理员这一信息存储于 Cookies 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
app.use(function (req, res, next) { req.cookies = new Cookies(req, res) let userInfo = req.cookies.get('userInfo') if (userInfo) { try { console.log('用户cookie信息', userInfo) req.userInfo = JSON.parse(userInfo) User.findById(req.userInfo._id).then(function (userInfo) { req.userInfo.isAdmin = Boolean(userInfo.isAdmin) next() }) } catch (e) { req.userInfo = {} next() } } else { next() } }) |
以上我们完成了用户的登录、登出等功能,并添加了管理员这一角色,目前前台界面中用户模块基本有了一个雏形,在下一篇,我们将会开发后台管理模块。
本文作者:穆英杰