首頁»NodeJS»Node.js+Express 開發之Cookie、Session 使用詳解

Node.js+Express 開發之Cookie、Session 使用詳解

來源:雨林星空 發布時間:2019-11-26 閱讀次數:

  為什么有cookie 和 session ?

  因為HTTP協議是沒有狀態的,當用戶再次訪問網站時,沒法判斷之前是否登陸過,于是就有了cookies和session,用來保存用戶的一些信息。

  cookie 和 session 區別?

  cookie 是存放在客戶端瀏覽器的,每個域名下通常限制為50個cookie,每個cookie 的值大小限制為4K。session 是存放在服務器端的,可以存儲無限大的數據,但大量的session,會占用較多的服務器內存。

  cookie 只能存放字符串類型數據,session可以存放任意類型數據。

  cookie 是保存在瀏覽器客戶端的,所以也很容易被提取,安全方面存在隱患。session 保存在服務器端相對安全。

  cookie的工作原理

  當用戶登錄網站成功,服務器會在返回響應數據的同時,將用戶的cookie信息也下發到客戶端,之后客戶端每次發起請求會攜帶著這個cookie,從而免去網站登錄的步驟。

  session的工作原理

  用戶的session數據保存在服務器內存中,服務器只下發一個session標識(session_id),它是一個唯一的隨機字串,被保存到cookie中,下次瀏覽器的請求攜帶著包含session_id的cookie,然后服務器在內存中查詢該session_id 是否有對應的數據,如果有則是已登錄用戶。

  看起來,session 技術相當于Cookie技術的升級,session是基于cookie的,但是cookie只是起到了 session_id 載體的作用,而url的查詢參數,http請求頭里的字段都可以起到session_id 載體的作用,所以沒有cookie也可以實現session。另外,用戶的session數據不僅可以存放在服務器內存中,也可以存放到文件或數據庫中,要持久化session 同時也要持久化cookie的session_id。

  nodejs+express 開發中 cookie 的使用

  node.js 的web框架 express 在4.x版本后,許多模塊不再包含在其中,而是需要單獨下載安裝。

  cookie 常用模塊是 cookie-parser,安裝命令如下:

npm install cookie-parser

  基本用法

  代碼示例:

let express = require("express");
let cookieParser = require("cookie-parser"); // 引用cookie-parser

let app = express();
app.use(cookieParser()); // 使用cookie中間件cookie-parser


// 首頁,讀取cookie
app.get("/", function (req, res) {
    console.log("name: " + req.cookies.name, "profile: " + JSON.stringify(req.cookies.profile));
    res.send("name: " + req.cookies.name + "<br/>" + "profile: " + JSON.stringify(req.cookies.profile));
});

// 登錄,注冊cookie
app.get("/login", function (req, res) {

    // 定義cookie參數對象
    let cookieOptions = {
        httpOnly: true,
        maxAge: 10 * 60 * 1000, // 10分鐘后cookie失效
    }

    // 創建cookie,值為字符串
    res.cookie("name", "xiaoyu", cookieOptions);

    // 創建cookie,值可以寫成json對象形式 {....} 、[...]
    res.cookie('profile', {
        age: '25',
        height: '160cm',
        weight: '50kg'
    }, cookieOptions);

    res.send("已注冊cookie");
});


// 退出,清除cookie
app.get("/exit", function (req, res) {
    res.clearCookie("name");
    res.clearCookie("profile");
    res.send("已清除cookie");
});

app.listen(3000);

  使用簽名cookie

  使用簽名 cookie,起防篡改功能。

  代碼示例:

let express = require("express");
let cookieParser = require("cookie-parser"); // 引用cookie-parser

let app = express();
app.use(cookieParser("1234567abcdefg")); // 使用cookie-parser,傳入簽名防篡改,可自定義一個復雜的字串


// 首頁,讀取cookie
app.get("/", function (req, res) {
    console.log("name: " + req.signedCookies.name, "profile: " + JSON.stringify(req.signedCookies.profile));
    res.send("name: " + req.signedCookies.name + "<br/>" + "profile: " + JSON.stringify(req.signedCookies.profile));
});

// 登錄,注冊cookie
app.get("/login", function (req, res) {

    // 定義cookie參數對象
    let cookieOptions = {
        httpOnly: true,
        maxAge: 10 * 60 * 1000, // 10分鐘后cookie失效
        signed: true // 使用簽名
    }

    // 創建cookie,值為字符串
    res.cookie("name", "xiaoyu", cookieOptions);

    // 創建cookie,值可以寫成json對象形式 {....} 、[...]
    res.cookie('profile', {
        age: '25',
        height: '160cm',
        weight: '50kg'
    }, cookieOptions);

    res.send("已注冊cookie");
});


// 退出,清除cookie
app.get("/exit", function (req, res) {
    res.clearCookie("name");
    res.clearCookie("profile");
    res.send("已清除cookie");
});

app.listen(3000);

   cookie 參數選項說明:

   domain:表示cookie在什么域名下有效,默認為當前網站域名。如果跨域訪問,A站域名為 A.test.com,B站域名為 B.test.com,那么在域A生產一個令域A和域B都能訪問的cookie就要將該cookie的domain設置為: ".test.com"

  expires:cookie過期時間,類型為Date。例如:expires: new Date(Date.now() + 10*60*1000)  表示10分鐘后cookie過期。如果沒有設置或者設置為0,那么該cookie 在關閉瀏覽器后失效。expires早在http/1.0中已經定義,max-age在http/1.1中定義, 現在基本都是http/1.1,expires已經被max-age屬性所取代,建議優先使用maxAge

  maxAge:和expires類似,設置cookie過期的時間,指明從現在開始,多少毫秒以后cookie到期。maxAge:10*60*1000  表示10分鐘后Cookie過期。 完全不寫 maxAge 項,只要關閉瀏覽器cookie就失效。maxAge:0  表示從客戶端刪除此cookie。  

  httpOnly:禁止JS腳本document.cookie 讀取cookie內容,防止XSS攻擊產生. 默認為false。建議設置為true

  path:cookie在什么路徑下有效,默認為'/'

  secure:當secure值為true時,cookie在HTTP中是無效,只在HTTPS中才有效。默認為false

  signed:使用簽名,起到防篡改功能。默認為false。  此項并不是加密,cookie值仍然被明文顯示出來,對于cookie的加密可自己使用md5、sha1、hmac、aes等方法,或使用中間件cookie-encrypter
 

  對 cookie 加密

  這里使用第三方模塊 cookie-encrypter 對cookie 進行加密。該模塊默認采用的是AES256 對稱加密算法

     安裝cookie-encrypter

npm install cookie-encrypter

  代碼示例

let express = require("express");
let cookieParser = require("cookie-parser"); 
let cookieEncrypter = require("cookie-encrypter"); // 引用cookie-encrypter 模塊

let app = express();
const secretKey = 'foobarbaz1234567foobarbaz1234567'; // 默認cookie-encrypter模塊使用的是 AES256 加密算法,須輸入32個字符
app.use(cookieParser(secretKey)); 
app.use(cookieEncrypter(secretKey)); // 傳入密鑰,加密cookie,主要是這句

app.get("/", function (req, res) {    
    console.log("name: " + req.signedCookies.name, "profile: " + JSON.stringify(req.signedCookies.profile));
    res.send("name: " + req.signedCookies.name + "<br/>" + "profile: " + JSON.stringify(req.signedCookies.profile));
});

app.get("/login", function (req, res) {
    let cookieOptions = {
        httpOnly: true,
        signed: true,
        maxAge: 10 * 60 * 1000,
        // plain: true  //  該選項是cookie-encrypter模塊的選項。等于true時,表示不再使用cookie-encrypter進行加密。
    };
    res.cookie('name', 'xiaoyu', cookieOptions);
    res.cookie('profile', {
        age: '25',
        height: '160cm',
        weight: '50kg'
    }, cookieOptions);
    res.send("已注冊cookie");
});

app.get("/exit", function (req, res) {
    res.clearCookie('name');
    res.clearCookie('profile');
    res.send("已清除cookie");
});

app.listen(3000);

  nodejs+express 開發中 session 的使用

  處理session常用的中間件之一是 express-session

  安裝 express-session 模塊,命令如下:

  npm install express-session

  代碼示例

let express = require("express");
let session = require("express-session");
let app = express();

app.use(session({
    secret: "nodejs world", 
    resave: false, 
    saveUninitialized: false, 
    name: "session_id", 
    rolling: true, 
    cookie: {
        path: '/',
        httpOnly: true,
        secure: false,
        maxAge: 30 * 60 * 1000 // 設置session_id的cookie有效時間,也是后臺session的有效時長。(默認為值為null,當關閉瀏覽器時,session_id cookie失效)。
    }
}));


app.get("/", function (req, res) {
    if (req.session.login) {
        res.send("歡迎您" + req.session.userName + ", " + req.sessionID);
    } else {
        res.send("你沒有登錄!");
    }

});

app.get("/login", function (req, res) {
    req.session.login = true;
    req.session.userName = "xiaoyu";
    res.send("您已經成功登錄");
});


app.get("/exit", function (req, res) {
    req.session.destroy();
    res.send("您已經退出");
});


app.listen(3000);

  session 配置選項說明

  secret: 對session_id cookie的簽名密鑰。

  resave: 強制保存 session 即使它并沒有變化。默認為true,建議設置成false

  saveUninitialized: 強制將未初始化的session存儲。默認為 true。 設置為true 不管用不用到session都會初始化。設置為false 用到session時才會去初始化。

  name: 這里設置session_id 的cookie的名字。默認名為 'connect.sid'

  rolling: 在每次請求時強行設置cookie,這將重置session-id 的 cookie過期時間。默認:false

  cookie:  session_id 的cookie 選項。缺省值是 { path: '/', httpOnly: true, secure: false, maxAge: null }

 

  將session 存放在 mongoDB 數據庫中

  session 默認存放在內存中,也可以存放到 redis,mongodb 等數據庫中。express 生態中都有相應模塊支持。

  將session存儲到mongodb 數據庫,可以安裝connect-mongo模塊支持

npm install connect-mongo

  代碼示例

let express = require("express");
let session = require("express-session");
let MongoStore = require('connect-mongo')(session);  // 引用 connect-mongo

let app = express();

app.use(session({
    secret: "nodejs world",
    resave: false,
    saveUninitialized: false, 
    name: "session_id",
    rolling: true, 
    cookie: {
        path: '/',
        httpOnly: true,
        secure: false, 
        maxAge: 30 * 60 * 1000  // session_id cookie 和 session的有效時長
    },
    store: new MongoStore({
     url: 'mongodb://localhost:27017/mydb', // 指定mongoDB 主機地址、端口、數據庫
     ttl: 30*60 // 設置session過期時間,時間到自動移除。單位秒。一般設置為30分鐘即可。未設置cookie:maxAge時有效。
    })
}));


app.get("/", function (req, res) {
    if (req.session.login) {
        res.send("歡迎您" + req.session.userName + ", " + req.sessionID);
    } else {
        res.send("你沒有登錄!");
    }
});

app.get("/login", function (req, res) {
    req.session.login = true;
    req.session.userName = "xiaoyu";
    res.send("您已經成功登錄");
});


app.get("/exit", function (req, res) {
    req.session.destroy();
    res.send("您已經退出");
});


app.listen(3000);

  將session 存放在 redis 數據庫中  

  將session存儲到redis 數據庫,可以安裝redis-mongo模塊支持。事先需安裝好redis的nodejs客戶端

npm install redis
npm install connect-redis

  代碼示例

let express = require("express");
let session = require("express-session");
let redis = require("redis"); // 引用redis客戶端
let RedisStore = require('connect-redis')(session); // 引用connect-redis
let app = express();

let redisClient = redis.createClient({ // 設置redis 主機地址、端口、數據庫、密碼
    host: "localhost",
    port: "6379",
    //password: "123456",
    db: 1
});

app.use(session({
    secret: "nodejs world",
    resave: false,
    saveUninitialized: false,  
    name: "session_id", 
    rolling: true, 
    cookie: {
        path: '/',
        httpOnly: true,
        secure: false, 
        maxAge: 30 * 60 * 1000 // session_id cookie 和 session的有效時長
    },
    store: new RedisStore({
        client: redisClient, // 指定redis客戶端
         ttl: 30 * 60, // 設置session過期時間,時間到自動移除。單位秒。一般設置為30分鐘即可。未設置cookie:maxAge時有效。      
         logErrors: true, // 是否打印redis出錯信息,默認false
        prefix: "sess:" // key前綴,默認為 "sess:"
    })
    
}));


app.get("/", function (req, res) {
    if (req.session.login) {
        res.send("歡迎您" + req.session.userName + ", " + req.sessionID);
    } else {
        res.send("你沒有登錄!");
    }

});

app.get("/login", function (req, res) {
    req.session.login = true;
    req.session.userName = "xiaoyu";
    res.send("您已經成功登錄");
});


app.get("/exit", function (req, res) {
    req.session.destroy();
    res.send("您已經退出");
});

app.listen(3000);

 

QQ群:WEB開發者官方群(515171538),驗證消息:10000
微信群:加小編微信 849023636 邀請您加入,驗證消息:10000
提示:更多精彩內容關注微信公眾號:全棧開發者中心(fsder-com)
網友評論(共0條評論) 正在載入評論......
理智評論文明上網,拒絕惡意謾罵 發表評論 / 共0條評論
登錄會員中心
6十1选号器