如何在Node.js中使用ExpressJS和Express Session进行会话管理

462 阅读9分钟

使用ExpressJS和Express Session在Node.js中进行会话管理

一个网站是基于HTTP协议的。HTTP是一个无状态协议,这意味着在每个请求和响应周期结束时,客户端和服务器都会忘记对方。

这就是会话的作用。会话将包含一些关于该客户的独特数据,以使服务器能够跟踪用户的状态。在基于会话的认证中,用户的状态被存储在服务器的内存或数据库中。

会话是如何工作的

当客户端向服务器发出登录请求时,服务器将创建一个会话并将其存储在服务器端。当服务器响应客户端时,它会发送一个cookie。这个cookie将包含存储在服务器上的会话的唯一ID,现在它将被存储在客户端。这个cookie将在每次向服务器请求时发送。

我们使用这个会话ID并查找保存在数据库或会话存储中的会话,以保持会话和cookie之间的一对一匹配。这将使HTTP协议连接具有状态。

会话和cookie之间的区别

正如你可能已经注意到的,我们引入了一个新的概念,叫做cookie。我们需要回答这样一个问题:会话和cookie之间的区别是什么?

Cookie是一个存储在浏览器中的键值对。浏览器将cookie附在每个发送到服务器的HTTP请求上。

在一个cookie中,你不能存储大量的数据。一个cookie不能存储任何形式的用户凭证或秘密信息。如果我们这样做,黑客可以很容易地掌握这些信息并窃取个人数据用于恶意活动。

另一方面,会话数据存储在服务器端,即一个数据库或一个会话存储。因此,它可以容纳更大的数据量。为了从服务器端访问数据,一个会话是用一个秘密密钥或一个会话ID来验证的,我们在每次请求时都会从cookie中得到这个ID。

前提条件

  • 在你的电脑上安装[Node.js运行时]。
  • 有关于[如何使用Node.js]的基本知识。
  • 基本了解如何[使用Expres.js]库创建一个[HTTP服务器]。

设置所需的环境和库

这是一个Node.js项目。它使用NPM来管理其依赖性。你需要创建一个新的项目目录,并使用node应用程序进行初始化。

npm init –y

这将生成一个package.json 文件,该文件将管理本项目教程的依赖关系。

以下库将帮助我们建立一个Node.js会话。

  • [Express]- Node.js的一个网络框架,用于创建HTTP网络服务器。Express提供了一个易于使用的API来与网络服务器交互。
  • [Express-session]- 一个HTTP服务器端框架,用于创建和管理会话中间件。本教程是关于会话的。因此Express-session库将是主要的焦点。
  • [Cookie-parser]- 用于解析cookie头,以便在服务器端建立会话时在浏览器上存储数据。

使用命令安装上述库。

npm install express express-session cookie-parser

Express-session选项以及如何使用它们

为了建立会话,你需要设置几个Express-session选项,如下所示。

const oneDay = 1000 * 60 * 60 * 24;
app.use(sessions({
    secret: "thisismysecrctekeyfhrgfgrfrty84fwir767",
    saveUninitialized:true,
    cookie: { maxAge: oneDay },
    resave: false 
}));
  • secret - 一个随机的唯一字符串密钥,用于验证会话。它被存储在一个环境变量中,不能暴露给公众。在生产环境中,这个密钥通常很长,而且是随机生成的。

  • resave - 取一个布尔值。它使会话被存储到会话存储区,即使在请求期间会话从未被修改。如果一个客户向服务器发出两个平行的请求,这可能会导致竞赛的情况。因此,当第二个请求结束时,对第一个请求的会话的修改可能会被覆盖。默认值是 。然而,这可能在某些时候改变。 是一个更好的选择。true false

  • saveUninitialized - 这允许任何 会话被发送到商店。当一个会话被创建但没有修改时,它被称为 。uninitialized uninitialized

  • cookie: { maxAge: oneDay } - 这设置了cookie的过期时间。浏览器将在设定的期限过后删除该cookie。该cookie将不会被附加到未来的任何请求中。在这种情况下,我们将 ,即通过以下算术计算出的单日。maxAge

// creating 24 hours from milliseconds
const oneDay = 1000 * 60 * 60 * 24;

设置会话中间件

为了初始化会话,我们将在各个HTTP请求的路由里面设置会话中间件。

当客户端发送请求时,服务器将设置一个会话ID,并将cookie设置为等于该会话ID。然后,该cookie被存储在浏览器的set cookie HTTP头中。每次浏览器(客户端)刷新时,存储的cookie将是该请求的一部分。

我们将创建一个简单的登录表单来演示。创建一个views 文件夹并添加以下内容。

  • 这里是登录表单(index.html)。
<html>
<head>
    <link rel="stylesheet" href="views/app.css">
</head>
<body>
    <form action="/user" method="post">
        <h2>Login</h2>
        <div class="input-field">
            <input type="text" name="username" id="username" placeholder="Enter Username">
        </div>
        <div class="input-field">
            <input type="password" name="password" id="password" placeholder="Enter Password">
        </div>
        <input type="submit" value="LogIn">
    </form>
</body>
</html>
  • 在views文件夹中添加一些CSS,使表单具有风格 (app.css)。
body {
    display: flex;
    justify-content: center;
}

form {
    display: flex;
    flex-direction: column;
}

.input-field {
    position: relative;
    margin-top: 2rem;
}

.input-field input {
    padding: 0.8rem;
}

form .input-field:first-child {
    margin-bottom: 1.5rem;
}

form input[type="submit"] {
    background: linear-gradient(to left, #4776E6, #8e54e9);
    color: white;
    border-radius: 4px;
    margin-top: 2rem;
    padding: 0.4rem;
}

让我们来设置服务器。创建一个app.js 文件并设置会话服务器,如下所示。

导入我们之前解释过的所有Node.js库

const express = require('express');
const cookieParser = require("cookie-parser");
const sessions = require('express-session');

初始化Express应用程序

const app = express();
const PORT = 4000;

添加Express-session选项

// creating 24 hours from milliseconds
const oneDay = 1000 * 60 * 60 * 24;

//session middleware
app.use(sessions({
    secret: "thisismysecrctekeyfhrgfgrfrty84fwir767",
    saveUninitialized:true,
    cookie: { maxAge: oneDay },
    resave: false
}));

解析HTML表单

这将帮助我们解析一个来自HTML文档的HTTP POST方法请求。我们还需要提供CSS样式,以格式化HTML表单的外观。添加以下Express方法来执行这些操作。

// parsing the incoming data
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

//serving public file
app.use(express.static(__dirname));

设置Cookie-parser

定义Cookie-parser的用法,以便服务器可以访问必要的选项来保存、读取和访问一个cookie。

// cookie parser middleware
app.use(cookieParser());

设置认证凭证

在这个例子中,我们正在使用一个简单的登录应用程序。为了验证用户,我在这个文件中指定了用户名和密码,分别为user1mypassword ,作为变量。

在生产环境中,这些凭证通常被保存在数据库中。在本教程中,为了简单起见,我们将它们存储在这些变量中。

//username and password
const myusername = 'user1'
const mypassword = 'mypassword'

// a variable to save a session
var session;

添加端点

我们必须在这里制作三个路由。

  1. http://localhost:4000/

这将渲染并提供HTML表单给客户端,让其填写登录凭证。如果用户已经登录了,我们将显示一个注销链接。

app.get('/',(req,res) => {
    session=req.session;
    if(session.userid){
        res.send("Welcome User <a href=\'/logout'>click to logout</a>");
    }else
    res.sendFile('views/index.html',{root:__dirname})
});
  1. http://localhost:4000/user

为了创建一个会话,用户将提交凭证。服务器将用现有用户的用户名和密码来验证这些在请求正文中收到的凭证。

如果证书是有效的。

  • 该用户将被授予必要的访问权。
  • 服务器将创建一个临时的用户会话,其中有一个被称为会话ID的随机字符串来识别这个会话。
  • 服务器将向客户的浏览器发送一个cookie。会话ID将被放在这个cookie里面。

一旦客户端浏览器保存了这个cookie,它就会把这个cookie和每个后续请求一起发送给服务器。服务器将根据会话ID验证该cookie。如果验证成功,用户将被允许访问服务器上的请求资源。

如果凭证无效,服务器将不授予该用户对资源的访问权。没有会话将被初始化,也没有cookie将被保存。

app.post('/user',(req,res) => {
    if(req.body.username == myusername && req.body.password == mypassword){
        session=req.session;
        session.userid=req.body.username;
        console.log(req.session)
        res.send(`Hey there, welcome <a href=\'/logout'>click to logout</a>`);
    }
    else{
        res.send('Invalid username or password');
    }
})
  1. http://localhost:4000/logout

这将定义注销的端点。当用户决定注销时,服务器将销毁(req.session.destroy(); )会话,并清除客户端的cookie。当maxAge 过期时,Cookies会在浏览器中被清除。

app.get('/logout',(req,res) => {
    req.session.destroy();
    res.redirect('/');
});

听取服务器的端口

app.listen(PORT, () => console.log(`Server Running at port ${PORT}`));

你的会话应用程序现在已经设置好了。运行该应用程序。

node app.js

这应该会在设定的端口4000上启动服务器。

An express server

在浏览器上打开服务器的路由http://localhost:4000/ ,你将得到这个登录表格。

A served express server html form

要通过服务器的认证,请提供服务器中指定的凭证:用户名为user1 ,密码为mypassword

Session user granted access

一旦你成功登录,将产生一个会话,并在浏览器中保存一个cookie。

在这种情况下,由于我们没有一个数据库来保存会话,我们将console.log(req.session) ,并看一下它的样子。如果你回到命令行,会话对象将被打印到控制台。

Node.js session

这些是你在生产环境中在服务器端保存到数据库(如MongoDB、PostgreSQL等)的相同值。

让我们看看保存在浏览器中的cookie值。

打开浏览器检查器工具 > 应用程序 > Cookies http://localhost:4000/。

Node.js browser cookies

每当你刷新这个页面时,请求就会连同这个cookie的值一起在这个localhost域内发送。如果它与会话存储的值相匹配,服务器就会对这个用户进行认证。

如果第三方能够读取cookie,这并不是一个安全问题。

客户端将无法修改cookie的内容,即使他们试图这样做,也会破坏该cookie的签名。这样一来,服务器就能检测到这种修改。

一个cookie里面并不携带任何有意义的数据。它只包含会话ID令牌。该cookie是加密的。它仍然要与用户会话保持一对一的关系。该cookie将一直有效,直到设置maxAge 过期或用户决定注销。

当用户注销时,会话将被销毁。没有会话可以与保存的cookie进行比较。用户将不得不再次登录,为新的登录会话创建一个会话ID。

总结

本教程就到此为止。这只是一个基本的例子,我希望它能帮助你理解在Node.js中使用Express.js和Express-session进行会话管理的概念。