自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Express-Session:SessionId 機(jī)制驅(qū)動(dòng)的一個(gè) Express 會(huì)話數(shù)據(jù)存儲(chǔ)庫

開發(fā) 前端 其他數(shù)據(jù)庫
express-session 是用來為 express 框架提供會(huì)話緩存支持的一個(gè)中間件。技術(shù)上是通過使用 sessionId 機(jī)制提供會(huì)話記憶支持的。

Express 是一個(gè) Node.js 的 Web 框架,提供對外服務(wù)器的功能。中間件則是 Express 提供的一種擴(kuò)展能力的插件機(jī)制。

express-session 就是 Express 的一個(gè)中間件。使用 sessionId 的機(jī)制,為用戶在網(wǎng)站訪問期間,提供會(huì)話數(shù)據(jù)的存儲(chǔ)支持。

技術(shù)實(shí)現(xiàn)上,express-session 就是為每個(gè)用戶生成唯一的一個(gè) sessionId(默認(rèn)通過名為 connect.sid 的 cookie 字段)并存儲(chǔ)在服務(wù)器上。在后續(xù)請求往返間,后端通過這個(gè) sessionId 就能拿到之前存儲(chǔ)的數(shù)據(jù),實(shí)現(xiàn)用戶訪問狀態(tài)的記憶。

注意:會(huì)話數(shù)據(jù)的存儲(chǔ)往往會(huì)借助文件系統(tǒng)或者數(shù)據(jù)庫系統(tǒng)(生產(chǎn)上通常叫緩沖數(shù)數(shù)據(jù)庫,比如 redis)等。express-session 管數(shù)據(jù)存儲(chǔ)叫 Store,默認(rèn)使用的是內(nèi)存(MemoryStore),不過生產(chǎn)上并不推薦。

圖片圖片

安裝 & 簡單使用

express-session 依賴 express,因此使用時(shí)需要保證 express 也存在。

$ npm install express express-session

下面是一個(gè)簡單的使用。

var express = require('express')
var session = require('express-session')

var app = express()

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))

secret 是必填項(xiàng),作為生成 sessio ID  的鹽值。resave、saveUninitialized 都是選填項(xiàng),不過由于這 2 個(gè)選項(xiàng)的默認(rèn)值會(huì)在未來版本修改,因此官方推薦顯式傳入。

express-session 是通過中間件方式注入到 express 應(yīng)用中的。經(jīng) express-session 處理后的請求實(shí)例 req 都包含一個(gè) .session 屬性,我們是通過在 .session 屬性上存儲(chǔ)信息,實(shí)現(xiàn)前后請求會(huì)話數(shù)據(jù)的保存的。

以下,我們將通過 2 個(gè)復(fù)雜一點(diǎn)的案例來介紹 express-session 的使用。

案例介紹

這里舉了 2 個(gè)例子,一個(gè)是統(tǒng)計(jì)用戶頁面訪問次數(shù),還有一個(gè)是用戶登錄的例子。

統(tǒng)計(jì)頁面訪問次數(shù)

我們先亮代碼(不是很多)。

var express = require('express')
var session = require('express-session')

var app = express()

// 1)
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))

app.use(function (req, res, next) {
  // 2)
  if (!req.session.views) {
    req.session.views = {}
  }

  // get the url pathname
  var pathname = req.path

  // 3)
  // count the views
  req.session.views[pathname] = (req.session.views[pathname] || 0) + 1

  next()
})

app.get('/foo', function (req, res, next) {
  res.send('you viewed this page ' + req.session.views['/foo'] + ' times')
})

app.get('/bar', function (req, res, next) {
  res.send('you viewed this page ' + req.session.views['/bar'] + ' times')
})

app.listen(3000)

這里我們起了一個(gè)監(jiān)聽在 3000 端口的服務(wù)器,對訪問 /foo、/bar 頁面的次數(shù)做了統(tǒng)計(jì)。

  1. 首先express(session({ ... })) 一下,做好會(huì)話存儲(chǔ)準(zhǔn)備,調(diào)用后,會(huì)在每一次請求(req)添加一個(gè) .session 對象屬性
  2. 頁面訪問數(shù)據(jù)存儲(chǔ)在 req.session.views 對象屬性上,初次訪問時(shí)是沒有這個(gè)對象的,就創(chuàng)建({})
  3. 接下來獲取某個(gè)訪問路徑下(req.path)的訪問次數(shù)(+1),結(jié)束

用戶登錄

用戶登錄是一個(gè)稍微復(fù)雜一點(diǎn)的例子,分登錄和退出,我們拆開來講。

首先,我們針對用戶登錄和未登錄狀態(tài)來區(qū)別顯示首頁內(nèi)容:

  • 用戶已登錄狀態(tài)下,顯示用戶名、暴露退出入口
  • 用戶未登錄狀態(tài)下,顯示登錄表單,登錄請求發(fā)送至 /login

以下是代碼實(shí)現(xiàn):

var escapeHtml = require('escape-html')
var express = require('express')
var session = require('express-session')

var app = express()

// 1)
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))

// 2.1) middleware to test if authenticated
function isAuthenticated (req, res, next) {
  if (req.session.user) next()
  else next('route')
}

// 2)
app.get('/', isAuthenticated, function (req, res) {
  // this is only called when there is an authentication user due to isAuthenticated
  res.send('hello, ' + escapeHtml(req.session.user) + '!' +
    ' <a href="/logout">Logout</a>')
})

// 3)
app.get('/', function (req, res) {
  res.send('<form actinotallow="/login" method="post">' +
    'Username: <input name="user"><br>' +
    'Password: <input name="pass" type="password"><br>' +
    '<input type="submit" text="Login"></form>')
})

// ...

app.listen(3000)

這里我們起了一個(gè)監(jiān)聽在 3000 端口的服務(wù)器,根據(jù)登錄狀態(tài)處理首頁展示邏輯。

  1. 還是老樣子,首先express(session({ ... })) 一下,做好會(huì)話存儲(chǔ)準(zhǔn)備,這一步會(huì)在每一次請求(req)添加一個(gè) .session 對象屬性
  2. 先跑第一個(gè) / 路徑邏輯,這一步會(huì)先經(jīng)過 isAuthenticated 中間件校驗(yàn)
  1. 用戶登錄后,我們會(huì)創(chuàng)建一個(gè) req.session.user 屬性存儲(chǔ)是用戶數(shù)據(jù),isAuthenticated 是檢查這個(gè)屬性又沒有的,有  req.session.user 話,就說明登陸了,展示用戶信息(next());沒有  req.session.user 的話,說明未登錄,則忽略用戶信息展示,跳轉(zhuǎn)至下一個(gè)路由處理(next('route'),也就是第 3 步)
  1. 經(jīng)過上一步,到這一步說明用戶未登錄,我們就發(fā)送一個(gè)登錄表單,讓用戶填寫。登錄表單包含 user、pass 字段信息。

接下來,我們來看看 /login 頁面的處理邏輯。

// ...

// 1)
app.post('/login', express.urlencoded({ extended: false }), function (req, res) {
  // login logic to validate req.body.user and req.body.pass
  // would be implemented here. for this example any combo works

  // regenerate the session, which is good practice to help
  // guard against forms of session fixation
  // 1)
  req.session.regenerate(function (err) {
    if (err) next(err)

    // store user information in session, typically a user id
    // 2)
    req.session.user = req.body.user

    // save the session before redirection to ensure page
    // load does not happen before session is saved
    // 3)
    req.session.save(function (err) {
      if (err) return next(err)
      // 4)
      res.redirect('/')
    })
  })
})

// ...
  1. 為了能正確處理 <form> 表單提交數(shù)據(jù),我們使用 express.urlencoded({ extended: false }) 中間件將 form 表單數(shù)據(jù)收集到 req.body 上
  2. 我們一上來并沒有立即對 req.body.user/req.body.pass 進(jìn)行校驗(yàn),而是調(diào)用了 req.session.regenerate() 重新生成用戶會(huì)話 sessionId,這能避免會(huì)話固定攻擊(session fixation attack)
  3. 接下來,為了做簡單演示,我們沒有校驗(yàn)密碼,而是直接將提交的用戶名存儲(chǔ)下來(req.session.user = req.body.user)
  4. 在重定向會(huì)首頁之前,我們又調(diào)用了 req.session.save() 將新 sessionId 下的 user 信息同步給 Store(默認(rèn)是緩存,實(shí)際生產(chǎn)往往是一個(gè)緩存數(shù)據(jù)庫(像 redis))
  5. 最后,重定到首頁,這時(shí)候頁面就顯示登錄用戶名了

再來看看退出登錄(/logout)的邏輯。

app.get('/logout', function (req, res, next) {
  // logout logic

  // clear the user from the session object and save.
  // this will ensure that re-using the old sessionId
  // does not have a logged in user
  // 1)
  req.session.user = null
  // 2)
  req.session.save(function (err) {
    if (err) next(err)

    // regenerate the session, which is good practice to help
    // guard against forms of session fixation
    // 3)
    req.session.regenerate(function (err) {
      if (err) next(err)
      // 4)
      res.redirect('/')
    })
  })
})
  1. 首先,我們將 req.session.user 置為空
  2. 然后,req.session.save() 將上面的修改同步到 Store
  3. 接著,通過調(diào)用  req.session.regenerate() 重新生成 sessionId,這塊跟登錄一樣,是為了避免會(huì)話固定攻擊
  4. 最后,重定到首頁,這時(shí)候頁面就未登錄狀態(tài)下的登錄框了

總結(jié)

express-session 是用來為 express 框架提供會(huì)話緩存支持的一個(gè)中間件。技術(shù)上是通過使用 sessionId 機(jī)制提供會(huì)話記憶支持的。

本文分別列舉了 2 個(gè)案例來說明 express-session 的使用:訪問次數(shù)和用戶登錄。不過需要注意的是,不管是登錄還是退出,都要有一個(gè)新生成 sessionId 的過程(req.session.regenerate()),這是為了避免會(huì)話固定攻擊。

責(zé)任編輯:武曉燕 來源: 寫代碼的寶哥
相關(guān)推薦

2020-08-07 10:40:56

Node.jsexpress前端

2024-02-27 08:50:21

格式化Express三方庫

2009-04-21 11:25:10

視頻通訊Express 200LifeSize

2009-06-14 21:59:55

ibmdwWebSphere

2009-09-10 10:19:15

CCIE

2021-08-10 18:36:02

Express原理面試

2024-02-06 10:04:49

Express框架repo

2010-12-30 11:13:36

卸載SQL Serve

2009-12-03 17:54:32

Visual Stud

2010-03-24 09:25:01

移動(dòng)數(shù)據(jù)中心

2011-08-29 14:33:02

Oracle存儲(chǔ)過程

2020-03-05 09:54:54

數(shù)據(jù)驅(qū)動(dòng)數(shù)據(jù)數(shù)據(jù)分析

2019-07-15 11:00:24

ReactNode前端

2013-06-14 09:27:51

Express.jsJavaScript

2010-12-01 09:09:46

Solaris 11

2020-09-29 07:54:05

Express 飛起

2021-09-26 05:05:46

GoFiber Express

2016-12-15 08:54:52

線程sessionopenSession

2015-09-10 17:53:32

阿明

2011-07-21 16:28:20

MySQL數(shù)據(jù)庫帶游標(biāo)的存儲(chǔ)過程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號