• 技术文章 >web前端 >js教程

    Node实战:运用Cookie&Session进行登录验证

    青灯夜游青灯夜游2022-12-01 20:53:27转载78

    大前端成长进阶课程:进入学习

    原文地址:https://ailjx.blog.csdn.net/article/details/127909213

    作者:海底烧烤店ai

    在前面的几节中我们已经创建并优化好了简易用户管理系统的项目结构,也对 Cookie-Session登录验证 的工作原理做了讲解,接下来我们将继续补充这个系统的功能,这一节我们将实战运用Cookie-Session来实现这个系统的登录验证功能。【相关教程推荐:nodejs视频教程

    什么?你还不了解sessioncookie!快去看看上篇文章吧:详解 Cookie-Session登录验证 的工作原理

    1️⃣ 定义页面路由

    vies目录下新建login.ejs

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
        <h1>登录页面</h1>
        <div>用户名:<input type="text" id="username"></div>
        <div>密码:<input type="password" id="password"></div>
        <div><button id="login">登录</button></div>
        <script>
            const uname = document.getElementById("username");
            const pwd = document.getElementById("password");
            const login = document.getElementById("login");
            login.onclick = () => {
                fetch('/api/login', {
                    method: 'POST',
                    body: JSON.stringify({
                        username: uname.value,
                        password: pwd.value
                    }),
                    headers: {
                        "Content-Type": "application/json"
                    }
                }).then(res => res.json()).then(res => {
                    // console.log(res);
                    if (res.ok) {
                        location.href = "/"
                    } else {
                        alert("用户名密码不匹配!")
                    }
                })
            }
        </script>
    </body>
    
    </html>

    注意:页面中请求的接口是POST /api/login请求

    routes目录下新建login.js,该文件定义login页面的页面路由:

    var express = require("express");
    var router = express.Router();
    
    /* GET login page. */
    router.get("/", function (req, res, next) {
        res.render("login");
    });
    
    module.exports = router;

    app.js中挂载页面路由:

    // 引入
    var loginRouter = require("./routes/login");
    // 挂载
    app.use("/login", loginRouter);

    启动项目,访问http://localhost:3000/login正常显示:

    在这里插入图片描述

    2️⃣ 定义API接口

    services/UserService.js中定义接口的模型(M层):

    const UserService = {
    	// .......
        // 登录查询
        login: (username, password) => {
        	// 向数据库查询该用户
            return UserModel.findOne({ username, password });
        },
    };

    controllers/UserController.js中定义接口的控制层(C层):

    const UserController = {
     	// ......
     	// 登录验证
        login: async (req, res, next) => {
            try {
                const { username, password } = req.body;
                const data = await UserService.login(username, password);
                // console.log(data);
                if (data) {
                    res.send({ ok: 1, msg: "登录成功!", data });
                } else {
                    res.send({ ok: 0, msg: "用户不存在,登录失败!" });
                }
            } catch (error) {
                console.log(error);
            }
        },
    };

    routes/users.js中定义Api路由:

    // 登录校验
    router.post("/login", UserController.login);

    至此登录页面就搭建好了:

    在这里插入图片描述

    3️⃣ 配置session

    在上一节Cookie-Session登录验证工作原理的介绍中我们知道:

    图一

    图一

    这个过程显然是比较复杂的,在express中有一个express-session模块可以大大降低我们的工作量,让我们站在巨人的肩膀上开发!

    下载express-session

    npm i express-session

    app.js中进行配置:

    // 引入express-session
    var session = require("express-session");
    
    // 配置session:需要放在在路由配置的前面
    app.use(
        session({
            name: "AilixUserSystem", // cookie名字
            secret: "iahsiuhaishia666sasas", // 密钥:服务器生成的session的签名
            cookie: {
                maxAge: 1000 * 60 * 60, // 过期时间:一个小时过期
                secure: false, // 为true时表示只有https协议才能访问cookie
            },
            resave: true, // 重新设置session后会重新计算过期时间
            rolling: true, // 为true时表示:在超时前刷新时cookie会重新计时;为false表示:在超时前无论刷新多少次,都是按照第一次刷新开始计时
            saveUninitialized: true, // 为true时表示一开始访问网站就生成cookie,不过生成的这个cookie是无效的,相当于是没有激活的信用卡
        })
    );

    配置好后,就会发现浏览器中有一个名为AilixUserSystemcookie

    在这里插入图片描述

    这是因为express-session会自动解析cookie和向前端设置cookie,相当于是图一中的3、6(前半部分:通过SessionId查询到Session ,我们不再需要手动对cookie进行操作。

    4️⃣ 权限验证

    在登录成功时设置session

    // controllers/UserController.js
    // ....
    // 登录校验
    login: async (req, res, next) => {
       try {
           const { username, password } = req.body;
           const data = await UserService.login(username, password);
           // console.log(data);
           if (data) {
               // 设置session:向session对象内添加一个user字段表示当前登录用户
               req.session.user = data; // 默认存在内存中,服务器一重启就没了
               res.send({ ok: 1, msg: "登录成功!", data });
           } else {
               res.send({ ok: 0, msg: "用户不存在,登录失败!" });
           }
       } catch (error) {
           console.log(error);
       }
    },

    我们向req.session中添加了一个user字段,来保存用户登录的信息,这一步相当于是 图一中的1(SessionId会由express-session模块自动生成)、2

    req.session是一个session对象,需要注意的是这个对象虽然存在于req中,但其实不同的人访问系统时他们的req.session是不同的,因为 req.session是根据我们设置的cookie(由express-session模块自动生成的AilixUserSystem )生成的,每一个人访问系统所生成的cookie是独一无二的,所以他们的req.session也是独一无二的。

    在收到请求时校验session,在app.js添加以下代码:

    // 设置中间件:session过期校验
    app.use((req, res, next) => {
        // 排除login相关的路由和接口
        // 这个项目中有两个,一个是/login的页面路由,一个是/api/login的post api路由,这两个路由不能被拦截
        if (req.url.includes("login")) {
            next();
            return;
        }
        if (req.session.user) {
            // session对象内存在user,代表已登录,则放行
            // 重新设置一下session,从而使session的过期时间重新计算(在session配置中配置了: resave: true)
            // 假如设置的过期时间为1小时,则当我12点调用接口时,session会在1点过期,当我12点半再次调用接口时,session会变成在1点半才会过期
            // 如果不重新计算session的过期时间,session则会固定的1小时过期一次,无论这期间你是否进行调用接口等操作
            // 重新计算session的过期时间的目的就是为了防止用户正在操作时session过期导致操作中断
            req.session.myData = Date.now();
            // 放行
            next();
        } else {
            // session对象内不存在user,代表未登录
            // 如果当前路由是页面路由,,则重定向到登录页
            // 如果当前理由是api接口路由,则返回错误码(因为针对ajax请求的前后端分离的应用请求,后端的重定向不会起作用,需要返回错误码通知前端,让前端自己进行重定向)
            req.url.includes("api")
                ? res.status(401).send({ msg: "登录过期!", code: 401 })
                : res.redirect("/login");
        }
    });

    注意:这段代码需要在路由配置的前面。

    这段代码中我们通过req.session.myData = Date.now();来修改session对象,从而触发session过期时间的更新(sessionmyData这个属性以及它的值 Date.now()只是我们修改session对象的工具,其本身是没有任何意义的),你也可以使用其它方法,只要能将req.session修改即可。

    因为我们这个项目是后端渲染模板的项目,并不是前后端分离的项目,所以在配置中间件进行session过期校验拦截路由时需要区分Api路由页面路由

    后端在拦截API路由后,向前端返回错误和状态码:

    在这里插入图片描述

    这个时候需要让前端自己对返回结果进行判断从而进行下一步的操作(如回到登录页或显示弹窗提示),该系统中前端是使用JavaScript内置的fetch来进行请求发送的,通过它来对每一个请求结果进行判断比较麻烦,大家可以自行改用axios,在axios的响应拦截器中对返回结果做统一的判断。

    5️⃣ 退出登录

    向首页(index.ejs)添加一个退出登录的按钮:

    <button id="exit">退出登录</button>

    为按钮添加点击事件:

    const exit = document.getElementById('exit')
    
    // 退出登录
    exit.onclick = () => {
      fetch("/api/logout").then(res => res.json()).then(res => {
        if (res.ok) {
          location.href = "/login"
        }
      })
    }

    这里调用了GET /api/logout接口,现在定义一下这个接口,在controllers/UserController.js中定义接口的控制层(C层):

    const UserController = {
     	// ......
        // 退出登录
        logout: async (req, res, next) => {
            // destroy方法用来清除cookie,当清除成功后会执行接收的参数(一个后调函数)
            req.session.destroy(() => {
                res.send({ ok: 1, msg: "退出登录成功!" });
            });
        },
    };

    routes/users.js中定义Api路由:

    // 退出登录
    router.get("/logout", UserController.logout);

    6️⃣ 链接数据库

    前面我们通过 req.session.user = data;设置的session默认是存放到内存中的,当后端服务重启时这些session就会被清空,为了解决这一问题我们可以将session存放到数据库中。

    安装connect-mongo

    npm i connect-mongo

    connect-mongoMongoDB会话存储,用于用Typescript编写的连接Express

    修改app.js

    // 引入connect-mongo
    var MongoStore = require("connect-mongo");
    
    // 配置session
    app.use(
        session({
            name: "AilixUserSystem", // cookie名字
            secret: "iahsiuhaishia666sasas", // 密钥:服务器生成的session的签名
            cookie: {
                maxAge: 1000 * 60 * 60, // 过期时间:一个小时过期
                secure: false, // 为true时表示只有https协议才能访问cookie
            },
            resave: true, // 重新设置session后会重新计算过期时间
            rolling: true, // 为true时表示:在超时前刷新时cookie会重新计时;为false表示:在超时前无论刷新多少次,都是按照第一次刷新开始计时
            saveUninitialized: true, // 为true时表示一开始访问网站就生成cookie,不过生成的这个cookie是无效的,相当于是没有激活的信用卡
            store: MongoStore.create({
                mongoUrl: "mongodb://127.0.0.1:27017/usersystem_session", // 表示新建一个usersystem_session数据库用来存放session
                ttl: 1000 * 60 * 60, // 过期时间
            }), // 存放数据库的配置
        })
    );

    至此,我们就实现了运用Cookie&Session进行登录验证/权限拦截的功能!

    更多node相关知识,请访问:nodejs 教程

    以上就是Node实战:运用Cookie&Session进行登录验证的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:csdn,如有侵犯,请联系admin@php.cn删除

    前端(VUE)零基础到就业课程:点击学习

    清晰的学习路线+老师随时辅导答疑

    自己动手写 PHP MVC 框架:点击学习

    快速了解MVC架构、了解框架底层运行原理

    专题推荐:nodejs​ node
    上一篇:Node学习之聊聊Cookie-Session登录验证的工作原理 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• win环境下node版本怎么切换?(升级降级)• 浅析node中如何优雅使用Socket.IO模块• 什么是模块化?聊聊Node模块化的那些事• 详解node中的包和包管理工具• nodejs可视化学习:事件循环【动图演示】• 聊聊怎么使用Node将Excel转为JSON
    1/1

    PHP中文网