nodejs session 原理及實戰

翻譯自:https://stormpath.com/blog/ev...前端

clipboard.png

一 Cookie

由於HTTP協議是沒有狀態的,但不少狀況下是須要一些信息的,好比在用戶登錄後、再次訪問網站時,無法判斷用戶是否登錄過。因而就有了cookies,用於在瀏覽器端保存用戶數據,它有以下特色
1 是在客戶端瀏覽器端纔有的
2 用於記錄信息,大小最大爲4K字節
3 若是使用了cookies,那麼任何對該域名的訪問都會帶上cookiesnode

目前新型網站更多的採用瀏覽器緩存,cookie會存在一些問題,好比你每次往服務器提交請求時,都會帶上cookie,不管是你訪問的是否是靜態圖片。數據庫

cookie例子:
clipboard.pngexpress

二 Session

session相似服務器端的cookie,保存於服務器端,相似於服務器緩存。用戶登錄了總須要驗證吧,那麼就在session中驗證便可,session和cookie是一一對應關係。瀏覽器

session的建立順序緩存

  1. 生成全局惟一標識符(sessionid);
  2. 開闢數據存儲空間。通常會在內存中建立相應的數據結構,但這種狀況下,系統一旦掉電,全部的會話數據就會丟失,若是是電子商務網站,這種事故會形成嚴重的後果。不過也能夠寫到文件裏甚至存儲在數據庫中,這樣雖然會增長I/O開銷,但session能夠實現某種程度的持久化,並且更有利於session的共享;
  3. 將session的全局惟一標示符發送給客戶端。
    問題的關鍵就在服務端如何發送這個session的惟一標識上。聯繫到HTTP協議,數據無非能夠放到請求行、頭域或Body裏,基於此,通常來講會有兩種經常使用的方式:cookie和URL重寫。

三 Set-Cookie

Cookie是如何被設置的呢?是被服務器返回的請求設置的。安全

clipboard.png

服務器會返回一個set-cookie的消息,通知瀏覽器要設置cookie了,因而瀏覽器會根據set-cookie裏的字段來設置信息了,好比上圖的信息就會設置session=r@rdegges.com服務器

四 實戰

咱們以client-session(express-session基本徹底同樣)爲例,爲項目配置session
1 安裝模塊cookie

var session = require('client-sessions');

2 配置session網絡

app.use(session({
  cookieName: 'session',
  secret: 'random_string_goes_here',
  duration: 30 * 60 * 1000,
  activeDuration: 5 * 60 * 1000,
}));

1)secret:一個隨機字符串,由於客戶端的數據都是不安全的,因此須要進行加密
2) duration:session的過時時間,過時了就必須從新設置
3) activeDuration: 激活時間,好比設置爲30分鐘,那麼只要30分鐘內用戶有服務器的交互,那麼就會被從新激活。

五 在Session中保存用戶信息

app.post('/login', function(req, res) {
  User.findOne({ email: req.body.email }, function(err, user) {
    if (!user) {
      res.render('login.jade', { error: 'Invalid email or password.' });
    } else {
      if (req.body.password === user.password) {
        
        // sets a cookie with the user's info
        req.session.user = user;
        // 這裏貌似有誤,只是set了session,返回這個sessionid,但但數據並不會set到這個cookie裏頭
        
        res.redirect('/dashboard');
      } else {
        res.render('login.jade', { error: 'Invalid email or password.' });
      }
    }
  });
});

六 Session層中間件

咱們固然不但願每一個請求都加上這一段,因此咱們使用express來作全局配置

app.use(function(req, res, next) {
  if (req.session && req.session.user) {
    User.findOne({ email: req.session.user.email }, function(err, user) {
      if (user) {
        req.user = user;
        delete req.user.password; // delete the password from the session
        req.session.user = user;  //refresh the session value
        res.locals.user = user;
      }
      // finishing processing the middleware and run the route
      next();
    });
  } else {
    next();
  }
});

若是用戶邏輯在沒有登錄時必須登錄,那咱們能夠繼續加一個路由

function requireLogin (req, res, next) {
  if (!req.user) {
    res.redirect('/login');
  } else {
    next();
  }
};

app.get('/dashboard', requireLogin, function(req, res) {
  res.render('dashboard.jade');
});

七 安全性

1 咱們能夠在登出時重置session

app.get('/logout', function(req, res) {
  req.session.reset();
  res.redirect('/');
});

還能夠加一些安全性
httpOnly:用來保證cookie只能經過http訪問,而不能用js來讀取
secure:強制使用https
ephemeral:關閉瀏覽器時同時關閉cookie

八 總結

Cookie和session因爲實現手段不一樣,所以也各有優缺點和各自的應用場景:

  1. 應用場景
    Cookie的典型應用場景是Remember Me服務,即用戶的帳戶信息經過cookie的形式保存在客戶端,當用戶再次請求匹配的URL的時候,帳戶信息會被傳送到服務端,交由相應的程序完成自動登陸等功能。固然也能夠保存一些客戶端信息,好比頁面佈局以及搜索歷史等等。

Session的典型應用場景是用戶登陸某網站以後,將其登陸信息放入session,在之後的每次請求中查詢相應的登陸信息以確保該用戶合法。固然仍是有購物車等等經典場景;

  1. 安全性
    cookie將信息保存在客戶端,若是不進行加密的話,無疑會暴露一些隱私信息,安全性不好,通常狀況下敏感信息是通過加密後存儲在cookie中,但很容易就會被竊取。而session只會將信息存儲在服務端,若是存儲在文件或數據庫中,也有被竊取的可能,只是可能性比cookie小了太多。

Session安全性方面比較突出的是存在會話劫持的問題,這是一種安全威脅,這在下文會進行更詳細的說明。整體來說,session的安全性要高於cookie;

  1. 性能
    Cookie存儲在客戶端,消耗的是客戶端的I/O和內存,而session存儲在服務端,消耗的是服務端的資源。可是session對服務器形成的壓力比較集中,而cookie很好地分散了資源消耗,就這點來講,cookie是要優於session的;
  2. 時效性
    Cookie能夠經過設置有效期使其較長時間內存在於客戶端,而session通常只有比較短的有效期(用戶主動銷燬session或關閉瀏覽器後引起超時);
  3. 其餘
    Cookie的處理在開發中沒有session方便。並且cookie在客戶端是有數量和大小的限制的,而session的大小卻只以硬件爲限制,能存儲的數據無疑大了太多。

咱們建了個前端自助學習QQ羣,面向-1-2年碼農,有興趣的不妨加入:370423482


繼續補充下,關於如何作一個完整的登錄

1 用戶端

通常來講應該使用https,並且密碼毫不能在網絡中明文傳輸,所以在往服務器傳輸時就應該先加密,常見的md5,但md5被破解,所以能夠用SHA512來加密 SHA256(password)

2 服務端

服務端須要對密碼再進行加密,由於全部客戶端的東西都是不安全的,萬一你的網絡被監聽了呢,所以會進行 SHA512(username+SHA512(password)+sault)的加密,這裏的sault爲隨機數,防止被脫庫了後被猜出密碼,因此須要附加一個隨機數,這個sault最好是存放到另外的數據庫中,防止由於存到一個庫中被脫庫中猜出

累了,有空再加

相關文章
相關標籤/搜索