溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Node怎么運用Cookie和Session進行登錄驗證

發(fā)布時間:2022-12-02 09:33:16 來源:億速云 閱讀:158 作者:iii 欄目:web開發(fā)

本篇內(nèi)容主要講解“Node怎么運用Cookie和Session進行登錄驗證”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“Node怎么運用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>
    <h2>登錄頁面</h2>
    <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正常顯示:

Node怎么運用Cookie和Session進行登錄驗證

2?? 定義API接口

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

const UserService = {
	// .......
    // 登錄查詢
    login: (username, password) => {
    	// 向數(shù)據(jù)庫查詢該用戶
        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);

至此登錄頁面就搭建好了:

Node怎么運用Cookie和Session進行登錄驗證

3?? 配置session

在上一節(jié)Cookie-Session登錄驗證工作原理的介紹中我們知道:

Node怎么運用Cookie和Session進行登錄驗證

圖一

這個過程顯然是比較復(fù)雜的,在express中有一個express-session模塊可以大大降低我們的工作量,讓我們站在巨人的肩膀上開發(fā)!

下載express-session

npm i express-session

app.js中進行配置:

// 引入express-session
var session = require("express-session");

// 配置session:需要放在在路由配置的前面
app.use(
    session({
        name: "AilixUserSystem", // cookie名字
        secret: "iahsiuhaishia666sasas", // 密鑰:服務(wù)器生成的session的簽名
        cookie: {
            maxAge: 1000 * 60 * 60, // 過期時間:一個小時過期
            secure: false, // 為true時表示只有https協(xié)議才能訪問cookie
        },
        resave: true, // 重新設(shè)置session后會重新計算過期時間
        rolling: true, // 為true時表示:在超時前刷新時cookie會重新計時;為false表示:在超時前無論刷新多少次,都是按照第一次刷新開始計時
        saveUninitialized: true, // 為true時表示一開始訪問網(wǎng)站就生成cookie,不過生成的這個cookie是無效的,相當于是沒有激活的信用卡
    })
);

配置好后,就會發(fā)現(xiàn)瀏覽器中有一個名為AilixUserSystemcookie

Node怎么運用Cookie和Session進行登錄驗證

這是因為express-session會自動解析cookie和向前端設(shè)置cookie,相當于是圖一中的3、6(前半部分:通過SessionId查詢到Session ,我們不再需要手動對cookie進行操作。

4?? 權(quán)限驗證

在登錄成功時設(shè)置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) {
           // 設(shè)置session:向session對象內(nèi)添加一個user字段表示當前登錄用戶
           req.session.user = data; // 默認存在內(nèi)存中,服務(wù)器一重啟就沒了
           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中,但其實不同的人訪問系統(tǒng)時他們的req.session是不同的,因為 req.session是根據(jù)我們設(shè)置的cookie(由express-session模塊自動生成的AilixUserSystem )生成的,每一個人訪問系統(tǒng)所生成的cookie是獨一無二的,所以他們的req.session也是獨一無二的。

在收到請求時校驗session,在app.js添加以下代碼:

// 設(shè)置中間件:session過期校驗
app.use((req, res, next) => {
    // 排除login相關(guān)的路由和接口
    // 這個項目中有兩個,一個是/login的頁面路由,一個是/api/login的post api路由,這兩個路由不能被攔截
    if (req.url.includes("login")) {
        next();
        return;
    }
    if (req.session.user) {
        // session對象內(nèi)存在user,代表已登錄,則放行
        // 重新設(shè)置一下session,從而使session的過期時間重新計算(在session配置中配置了: resave: true)
        // 假如設(shè)置的過期時間為1小時,則當我12點調(diào)用接口時,session會在1點過期,當我12點半再次調(diào)用接口時,session會變成在1點半才會過期
        // 如果不重新計算session的過期時間,session則會固定的1小時過期一次,無論這期間你是否進行調(diào)用接口等操作
        // 重新計算session的過期時間的目的就是為了防止用戶正在操作時session過期導(dǎo)致操作中斷
        req.session.myData = Date.now();
        // 放行
        next();
    } else {
        // session對象內(nèi)不存在user,代表未登錄
        // 如果當前路由是頁面路由,,則重定向到登錄頁
        // 如果當前理由是api接口路由,則返回錯誤碼(因為針對ajax請求的前后端分離的應(yīng)用請求,后端的重定向不會起作用,需要返回錯誤碼通知前端,讓前端自己進行重定向)
        req.url.includes("api")
            ? res.status(401).send({ msg: "登錄過期!", code: 401 })
            : res.redirect("/login");
    }
});

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

這段代碼中我們通過req.session.myData = Date.now();來修改session對象,從而觸發(fā)session過期時間的更新(sessionmyData這個屬性以及它的值 Date.now()只是我們修改session對象的工具,其本身是沒有任何意義的),你也可以使用其它方法,只要能將req.session修改即可。

因為我們這個項目是后端渲染模板的項目,并不是前后端分離的項目,所以在配置中間件進行session過期校驗攔截路由時需要區(qū)分Api路由頁面路由。

后端在攔截API路由后,向前端返回錯誤和狀態(tài)碼:

Node怎么運用Cookie和Session進行登錄驗證

這個時候需要讓前端自己對返回結(jié)果進行判斷從而進行下一步的操作(如回到登錄頁或顯示彈窗提示),該系統(tǒng)中前端是使用JavaScript內(nèi)置的fetch來進行請求發(fā)送的,通過它來對每一個請求結(jié)果進行判斷比較麻煩,大家可以自行改用axios,在axios的響應(yīng)攔截器中對返回結(jié)果做統(tǒng)一的判斷。

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"
    }
  })
}

這里調(diào)用了GET /api/logout接口,現(xiàn)在定義一下這個接口,在controllers/UserController.js中定義接口的控制層(C層):

const UserController = {
 	// ......
    // 退出登錄
    logout: async (req, res, next) => {
        // destroy方法用來清除cookie,當清除成功后會執(zhí)行接收的參數(shù)(一個后調(diào)函數(shù))
        req.session.destroy(() => {
            res.send({ ok: 1, msg: "退出登錄成功!" });
        });
    },
};

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

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

6?? 鏈接數(shù)據(jù)庫

前面我們通過 req.session.user = data;設(shè)置的session默認是存放到內(nèi)存中的,當后端服務(wù)重啟時這些session就會被清空,為了解決這一問題我們可以將session存放到數(shù)據(jù)庫中。

安裝connect-mongo

npm i connect-mongo

connect-mongo是MongoDB會話存儲,用于用Typescript編寫的連接Express。

修改app.js

// 引入connect-mongo
var MongoStore = require("connect-mongo");

// 配置session
app.use(
    session({
        name: "AilixUserSystem", // cookie名字
        secret: "iahsiuhaishia666sasas", // 密鑰:服務(wù)器生成的session的簽名
        cookie: {
            maxAge: 1000 * 60 * 60, // 過期時間:一個小時過期
            secure: false, // 為true時表示只有https協(xié)議才能訪問cookie
        },
        resave: true, // 重新設(shè)置session后會重新計算過期時間
        rolling: true, // 為true時表示:在超時前刷新時cookie會重新計時;為false表示:在超時前無論刷新多少次,都是按照第一次刷新開始計時
        saveUninitialized: true, // 為true時表示一開始訪問網(wǎng)站就生成cookie,不過生成的這個cookie是無效的,相當于是沒有激活的信用卡
        store: MongoStore.create({
            mongoUrl: "mongodb://127.0.0.1:27017/usersystem_session", // 表示新建一個usersystem_session數(shù)據(jù)庫用來存放session
            ttl: 1000 * 60 * 60, // 過期時間
        }), // 存放數(shù)據(jù)庫的配置
    })
);

到此,相信大家對“Node怎么運用Cookie和Session進行登錄驗證”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI