前言
在上一节中,完成了用户的注册与登录,但是并没有保持用户登录,一刷新浏览器登录状态就没有了。所以在本节内容中将实现用户登录状态的保持,同时进行普通用户与博客管理员的区别,并且实现用户登出接口。
Cookie
想要维持住登录状态,就得借用 Cookie,Cookie 是服务器给客户端发的一段数据,可以比作通行证,客户端需要保存这段数据,不得随意删除。此后客户端每次访问服务器的时候都要携带上这段数据,这样服务器就能通过这段数据来确认用户的身份了。
Cookie 一般有两个作用:
第一个就是识别用户身份,比如用户 a 访问了 tlin.com ,那么 tflin.com 的服务器就会给 a 返回一段数据 [uid = 1],以后 a 不管访问 tflin.com 的任何页面都会携带上 [uid = 1] 这段数据,这样就能根据这段数据进行身份识别了。
第二个就是记录历史,也就是比如那些购物网站上的未登录的购物车,同样是借用 Cookie 。当 a 将商品介入购物车时,可以使用 Js 对 Cookie 进行修改,保存相应的记录。这样一来,关闭网页后,即使用户没有登录,再次打开网页,商品依旧安安静静的躺在购物车里。
保持用户登录
在本项目中,使用 Cookies 模块来设置 Cookie,这是他的官方文档 Cookies API。
我们先在项目的入口文件 app.js 中引入 Cookies 模块并进行中间件设置,在 app.js 添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const Cookies = require("cookies");
app.use((req, res, next) => { req.cookies = new Cookies(req, res); req.userInfo = {}; if (req.cookies.get("userInfo")) { req.userInfo = JSON.parse(req.cookies.get("userInfo")) } next(); });
|
然后在修改登录接口,在其登录成功的时候设置 cookie 信息,将 routes/api 中的登录接口修改为如下代码:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
router.post("/user/login", (req, res, next) => { let username = req.body.username; let password = req.body.password; console.log(password); if (username === "") { responseData.code = 1; responseData.message = "用户名不能为空!"; res.json(responseData); return; } if (password === "") { responseData.code = 2; responseData.message = "密码不能为空!"; res.json(responseData); return; } userModel.findOne({username: username}, (err, user) => { if (user) { if (user.password === password) { responseData.message = "登录成功!"; responseData.userInfo = { username: user.username, userid: user._id }; req.cookies.set("userInfo", JSON.stringify(responseData.userInfo)); res.json(responseData); return; } else { responseData.code = 5; responseData.message = "密码不正确!"; res.json(responseData); return; } } else { responseData.code = 6; responseData.message = "该用户名不存在!"; res.json(responseData); return; } }); });
|
这个时候我们已经将 cookie 的相关设置配置完成,当在用户登录成功的时候,服务器向客户端发送一个 cookie 信息,并且将 cookie 信息存到 req..userInfo 中,就可以将 req.userInfo 当做数据绑定给模板引擎。模板引擎则根据 req.userInfo 是否存在来判断用户是否已登录。
首先先在 /routes/main.js 中将 req.userInfo 分配给模板引擎:
1 2 3 4 5 6 7 8
| router.get("/", (req, res) => { res.render("main/index", { userInfo: req.userInfo }); });
|
接着就可在前台的页面 views/main/index.ejs 中使用所绑定的数据了,并以此来判断用户是否登录,思路如下:
如果 userInfo 存在则渲染用户信息面板,若不存在则渲染登录/注册面板
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| <div class="col-md-4"> <%if (!userInfo.userid) {%> <div id="login"> <h2>登录</h2> <div class="input-group"> <span class="input-group-addon">用户</span> <input type="text" class="form-control" name="username" placeholder="请输入用户名"> </div> <br> <div class="input-group"> <span class="input-group-addon">密码</span> <input type="password" class="form-control" name="password" placeholder="请输入密码"> </div> <br> <button type="button" name="button" class="btn btn-primary form-control" id="login-btn">登录</button> <br><br> <a href="javascripts:;" class="col-md-offset-4">没有账号?点击注册</a> <div class="alert alert-success alert-dismissable hide" role="alert"> <button class="close" type="button">×</button> <span>恭喜您操作成功!</span> </div> </div> <div id="reg" class="hide"> <h2>注册</h2> <div class="input-group"> <span class="input-group-addon">用户名称</span> <input type="text" class="form-control" name="username" placeholder="请输入用户名"> </div> <br> <div class="input-group"> <span class="input-group-addon">输入密码</span> <input type="password" class="form-control" name="password" placeholder="请输入密码"> </div> <br> <div class="input-group"> <span class="input-group-addon">确认密码</span> <input type="password" class="form-control" name="repassword" placeholder="请再次输入密码"> </div> <br> <button type="button" name="button" class="btn btn-primary form-control" id="reg-btn">注册</button> <br><br> <a href="javascripts:;" class="col-md-offset-4">已有账号?点击登录</a> <div class="alert alert-success alert-dismissable hide" role="alert"> <button class="close" type="button">×</button> <span>恭喜您操作成功!</span> </div> </div> <%} else {%> <div id="user-info"> <div class="panel panel-primary"> <div class="panel-heading">用户面板</div> <div class="panel-body"> <h3>欢迎,<%=userInfo.username%>!</h3> <p> <button type="button" name="button" class="btn btn-danger form-control">注销</button> </p> </div> </div> </div> <%}%> </div>
|
改完前台模板,我们的登录的 ajax 请求登录成功后的函数也要进行相应的修改,将登录成功后隐藏登录面板改为刷新页面,因为此时 cookie 已存在,所以刷新页面后,模板会自动渲染出用户信息面板:
1 2 3 4 5 6 7 8 9 10
| success: (result) => { if (result.code) { $warningBox.find("span").html("警告:" + result.message); $warningBox.addClass("alert-danger") $warningBox.removeClass("hide alert-success"); } else { window.location.reload(); } }
|
最后我们在客户端浏览器中进行测试,发现此时用户登陆后,无论怎么刷新,还是保持着登录状态。
用户登出接口
用户登出接口则只要将 cookie 清空即可,在 /routes/api.js 中添加如下代码:
1 2 3 4 5 6
| router.get("/user/logout", (req, res, next) => { req.cookies.set("userInfo", null); res.json(responseData); });
|
然后在前端用 ajax 请求:
1 2 3 4 5 6 7 8 9 10 11 12
| $logoutBtn.on("click", () => { $.ajax({ type: "get", url: "/api/user/logout", success: (result) => { if (result) { window.location.reload(); } } }); });
|
重启服务器进行测试:
到此,用户的登录注册及登出完成。
管理员与普通用户的区别
在数据库中,用户集合中有一个字段为 isadmin 这个字段就是是否是管理员,默认为 false,我们可以根据这个字段来判断当前登录的用户是否是管理员。具体步骤是将其从数据库中读取出来然后存放到 req.userInfo 中,与其他页面共享,绑定到模板引擎中,根据 isadmin 的值渲染不同的界面。
在项目的入口文件 app.js 先将用户的模型引用进来:
1 2
| const userModel = require("./models/user");
|
再cookies 配置的中间件中修改为如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| app.use((req, res, next) => { req.cookies = new Cookies(req, res); req.userInfo = {}; if (req.cookies.get("userInfo")) { req.userInfo = JSON.parse(req.cookies.get("userInfo")); userModel.findById(req.userInfo.userid).then((user) => { req.userInfo.isadmin = user.isadmin; next(); });
} else { next(); } });
|
然后将博客主页的模板中的用户面板部分修改为如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <div id="user-info"> <div class="panel panel-primary"> <div class="panel-heading">用户面板</div> <div class="panel-body"> <%if (userInfo.isadmin) {%> <h3>欢迎尊贵的管理员,<%=userInfo.username%>!</h3> <p> <button type="button" name="button" class="btn btn-danger form-control">进入控制台</button> </p> <%} else {%> <h3>欢迎您,<%=userInfo.username%>!</h3> <%}%> <p> <button type="button" name="button" id="logout" class="btn btn-danger form-control">注销</button> </p> </div> </div> </div>
|
接着把数据库中的 admin 账户的 isadmin 置为 true 然后重启服务器到客户端浏览器上测试一下:
此时管理员账户与普通用户账户已经区分出来了。