17. Node.js 項目的登錄登出功能

本項目基于 node.js 的 express 框架欲侮,數(shù)據(jù)庫使用 mongoDB

步驟

  1. 初始化 package.json:
    項目目錄下執(zhí)行命令 npm init -y
  2. 創(chuàng)建 git 倉庫:
    項目目錄執(zhí)行命令 git init
  3. 新建項目說明文件 README.md
  4. 安裝項目核心包 express 與 mongoose
  5. 配置模板引擎 express-art-template
  6. 創(chuàng)建 Views 目錄以存放 html 頁面文件
  7. 安裝 bootstrap 和 jquery
  8. 提取路由模塊并設計路由
  9. 設計用戶數(shù)據(jù) Schema
  10. 處理注冊頁面:
    10.1 配置解析表單 POST 請求體插件 body-parser
    10.2 配置密碼加密插件 blueimp-md5
    10.3 配置 express-session 插件削彬,通過 session 保存登錄狀態(tài)
  11. 處理登錄頁面
  12. 處理退出頁面

路由設計

路徑 方法 get 參數(shù) post 參數(shù) 是否需要登陸 功能
/ GET 渲染首頁
/register GET 渲染注冊頁面
/register POST email曼库、nickname西雀、password 處理注冊請求
/login GET 渲染登錄頁面
/login POST email、password 處理登錄請求
/logout GET 處理退出請求

表單的同步提交和異步提交

同步提交與優(yōu)化:
表單具有默認提交行為厨钻,默認是同步的琐脏。同步表單提交,瀏覽器會鎖死(轉圈兒)等待服務端的響應結果吴裤。表單同步提交后鳖眼,無論服務端響應的是什么,瀏覽器都會把響應的結果直接渲染到當前容器中嚼摩,覆蓋掉當前頁面钦讳。這種交互方式給人不好的用戶體驗。為了避免這種不好的交互體驗枕面,可以對當前頁面進行重新渲染愿卒。
(場景:用戶注冊時提示郵箱或密碼已存在)

router.post('/register', function (req, res) {
  // 1. 獲取表單提交的數(shù)據(jù) req.body  ...省略代碼...
  // 2. 查詢數(shù)據(jù)庫判斷該用戶是否存在 ...省略代碼...
  // 3. 存在則得到查詢結果 data
    if (data) {
    // 4. 響應結果
    return res.render('register.html', {
    err_message: '郵箱或密碼已存在', // 回復后用于瀏覽器將報錯信息渲染到頁面
    form: req.body  // 回復后用于瀏覽器將用戶信息渲染到頁面
    })
})
<!--渲染 err_message-->
<p>{{ err_message }}</p>
<!--表單提交的默認行為是發(fā)送 url 為 /register 的post請求-->
<form id="register_form" method="post" action="/register">
      <div class="form-group">
        <label for="email">郵箱</label>
        <input type="email" class="form-control" id="email" name="email" placeholder="Email" autofocus value="{{ form && form.email }}">
      </div>
      <div class="form-group">
        <label for="nickname">昵稱</label>
        <input type="text" class="form-control" id="nickname" name="nickname" placeholder="Nickname" value="{{ form && form.nickname }}">
      </div>
      <div class="form-group">
        <label for="password">密碼</label>
        <input type="password" class="form-control" id="password" name="password" placeholder="Password">
      </div>
      <button type="submit" class="btn btn-success btn-block">注冊</button>
    </form>

異步提交:
ajax 等異步交互方式誕生后,表單就可以通過 ajax 進行異步提交了潮秘。異步表單提交琼开,瀏覽器不會等待服務端的響應結果,也不會再有響應結果返回后覆蓋掉當前頁面的糟糕交互體驗了枕荞。但需要注意的是柜候,同步交互時服務端可以通過 res.redirect 對客戶端進行重定向搞动,但異步交互時,服務端重新定向是無效的渣刷。因此只能客戶端判斷跳轉鹦肿。

<script>
    $("#register_form").on('submit', function (e) {
        e.preventDefault() //禁止表單的默認提交行為
        var formData = $(this).serialize()
        $.ajax({
            url: '/register',
            type: 'post',
            data: formData,
            dataType: 'json',
            success: function (data) {
                var err_code = data.err_code
                if (err_code === 0) {
                    window.location.href = '/' // 服務端重定向針對異步請求無效
                } else if (err_code === 1) {
                    window.alert('郵箱或昵稱已存在!')
                } else if (err_code === 500) {
                    window.alert('服務器忙辅柴,請稍后重試箩溃!')
                }
            }
        })
    })
</script>

配置密碼加密插件 md5

用戶注冊時需要存儲用戶的密碼到數(shù)據(jù)庫,為了防止密碼泄露碌嘀,保證用戶密碼的安全性涣旨,我們需要對用戶密碼進行加密,md5 是一種常用的加密方式股冗。在 github 查找 node md5 找到 node 中使用的 md5 插件:blueimp-md5

github 找 md5 插件

  • 安裝:npm i blueimp-md5
  • 使用:
    var md5 = require('blueimp-md5')
    然后直接使用 md5(password)方法即可加密

Cookie 與 Session

參考博客:https://www.cnblogs.com/whgk/p/6422391.html

Cookie和Session之間的區(qū)別和聯(lián)系

假如一個咖啡店有喝5杯咖啡免費贈一杯咖啡的優(yōu)惠霹陡,然而一次性消費5杯咖啡的機會微乎其微,這時就需要某種方式來紀錄某位顧客的消費數(shù)量止状。想象一下其實也無外乎下面的幾種方案:

1烹棉、該店的店員很厲害,能記住每位顧客的消費數(shù)量导俘,只要顧客一走進咖啡店,店員就知道該怎么對待了剔蹋。這種做法就是協(xié)議本身支持狀態(tài)旅薄。但是http協(xié)議本身是無狀態(tài)的

2、發(fā)給顧客一張卡片泣崩,上面記錄著消費的數(shù)量少梁,一般還有個有效期限。每次消費時矫付,如果顧客出示這張卡片凯沪,則此次消費就會與以前或以后的消費相聯(lián)系起來。 顧客就相當于瀏覽器买优。這種做法就是在客戶端保持狀態(tài)妨马。也就是cookie。

3杀赢、發(fā)給顧客一張會員卡烘跺,除了卡號之外什么信息也不紀錄,每次消費時脂崔,如果顧客出示該卡片滤淳,則店員在店里的紀錄本上找到這個卡號對應的紀錄添加一些消費信息。這種做法就是在服務器端保持狀態(tài)砌左。也就是session脖咐。

Cookie通過在客戶端記錄信息確定用戶身份铺敌,Session通過在服務器端記錄信息確定用戶身份。session和cookie的作用是類似的屁擅,都是為了存儲用戶相關的信息偿凭。

Cookie的機制

在網(wǎng)站中,http請求是無狀態(tài)的煤蹭,也就是說笔喉,即使第一次和服務器連接后并且登錄成功后,第二次請求服務器依然不能知道當前請求是哪個用戶硝皂。cookie的出現(xiàn)就是為了解決這個問題:瀏覽器請求服務器訪問web站點時常挚,服務器通過 http 響應將Cookie數(shù)據(jù)回給瀏覽器,瀏覽器將cookie數(shù)據(jù)存放在客戶端內存中稽物,當該用戶發(fā)送第二次請求的時候奄毡,就會自動的把上次請求存儲的cookie數(shù)據(jù)自動攜帶給服務器,服務器通過瀏覽器攜帶的數(shù)據(jù)就能識別當前用戶贝或。

cookie中的Domain和Path屬性標識了這個cookie是哪一個網(wǎng)站發(fā)送給瀏覽器的吼过;Expires屬性標識了cookie的有效時間:

  1. 如果對Expires屬性進行有效時間設置,當cookie的有效時間過了之后咪奖,這些數(shù)據(jù)就被自動刪除了盗忱;此時會話cookie保存在硬盤上。關閉瀏覽器后再次打開羊赵,這些cookie依然有效趟佃,直到超過設定的有效時間。存儲在硬盤上的cookie可以在不同的瀏覽器進程間共享昧捷,比如兩個IE窗 口闲昭。

  2. 如果不設置過期時間,則表示這個cookie生命周期為瀏覽器會話期間靡挥,只要關閉瀏覽器窗口序矩,cookie就消失。這種生命期為瀏覽會話期的cookie被稱為會話cookie跋破。會話cookie一般不保存在硬盤上簸淀,而是保存在內存里。

特點:cookie存儲在本地瀏覽器毒返,且存儲數(shù)據(jù)量有限啃擦,不同的瀏覽器有不同的存儲大小,但一般不超過4KB饿悬。因此使用cookie只能存儲一些小量的數(shù)據(jù)令蛉。
Session的機制

Session的機制

瀏覽器請求服務器訪問web站點時,程序需要為客戶端的請求創(chuàng)建一個session的時候,服務器首先會檢查這個客戶端請求是否已經(jīng)包含了一個session標識珠叔、稱為SESSIONID蝎宇,如果已經(jīng)包含了一個sessionid則說明以前已經(jīng)為此客戶端創(chuàng)建過session,服務器就按照sessionid把這個session檢索出來使用祷安,如果客戶端請求不包含session id姥芥,則服務器為此客戶端創(chuàng)建一個session并且生成一個與此session相關聯(lián)的session id,sessionid 的值應該是一個既不會重復汇鞭,又不容易被找到規(guī)律以仿造的字符串凉唐,這個sessionid將在本次響應中返回到客戶端保存,保存這個sessionid的方式就可以是cookie霍骄,這樣在交互的過程中台囱,瀏覽器可以自動的按照規(guī)則把這個標識發(fā)回給服務器,服務器根據(jù)這個sessionid就可以找得到對應的session读整。

一般情況下簿训,服務器會在一定時間內(默認20分鐘)保存這個session,過了時間限制米间,就會銷毀這個session强品。在銷毀之前,程序員可以將用戶的一些數(shù)據(jù)以Key和Value的形式暫時存放在這個session中屈糊。默認 Session 數(shù)據(jù)是內存存儲的的榛,服務器一旦重啟就會丟失,也有使用數(shù)據(jù)庫將這個session序列化后保存起來的逻锐,這樣的好處是沒了時間的限制夫晌,壞處是隨著時間的增加,這個數(shù)據(jù)庫會急速膨脹谦去,特別是訪問量增加的時候慷丽。一般還是采取前一種方式蹦哼,以減輕服務器壓力鳄哭。

特點:cookie存儲在本地瀏覽器,而session存儲在服務器纲熏。存儲在服務器的數(shù)據(jù)會更加的安全妆丘,不容易被竊取。但會占用服務器的資源局劲。

在 Express 中配置使用 express-session 插件

在 express 中勺拣,默認不支持 Session 和 Cookie,但是我們可以使用第三方中間件:express-session 來解決:

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

app.use(session({
  secret: 'keyboard cat', //配置加密字符串
  resave: false,
  saveUninitialized: true,
  // cookie: { secure: true } cookie 安全限制 https 協(xié)議
}))
  1. secret屬性是配置加密字符串鱼填,它會在原有加密基礎之上和這個字符串拼起來去加密药有,加密后的字符串作為 session id 發(fā)送給瀏覽器。目的是為了增加安全性,防止客戶端惡意偽造
  2. saveUninitialized 屬性為 true 則無論你是否使用 Session愤惰,都默認直接分配一個session id 給客戶端苇经。為 false 則真正存數(shù)據(jù)的時候才會分配 session id 給客戶端
  3. 當secure屬性設置為true時,cookie只有在https協(xié)議下才能上傳到服務器宦言,而在http協(xié)議下是沒法上傳的扇单,所以也不會被竊聽。
  • 使用:
    當把這個插件配置好之后奠旺,我們可以通過 req.session 來發(fā)訪問和設置 Session 成員蜘澜,例如:
// 添加 Session 數(shù)據(jù)
req.session.foo = 'bar'

// 訪問 Session 數(shù)據(jù)
req.session.foo
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市响疚,隨后出現(xiàn)的幾起案子鄙信,更是在濱河造成了極大的恐慌,老刑警劉巖稽寒,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扮碧,死亡現(xiàn)場離奇詭異,居然都是意外死亡杏糙,警方通過查閱死者的電腦和手機慎王,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宏侍,“玉大人赖淤,你說我怎么就攤上這事×潞樱” “怎么了咱旱?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绷耍。 經(jīng)常有香客問我吐限,道長,這世上最難降的妖魔是什么褂始? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任诸典,我火速辦了婚禮,結果婚禮上崎苗,老公的妹妹穿的比我還像新娘狐粱。我一直安慰自己,他們只是感情好胆数,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布肌蜻。 她就那樣靜靜地躺著,像睡著了一般必尼。 火紅的嫁衣襯著肌膚如雪蒋搜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機與錄音豆挽,去河邊找鬼酸休。 笑死,一個胖子當著我的面吹牛祷杈,可吹牛的內容都是我干的斑司。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼但汞,長吁一口氣:“原來是場噩夢啊……” “哼宿刮!你這毒婦竟也來了?” 一聲冷哼從身側響起私蕾,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤僵缺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后踩叭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磕潮,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年容贝,在試婚紗的時候發(fā)現(xiàn)自己被綠了自脯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡斤富,死狀恐怖膏潮,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情满力,我是刑警寧澤焕参,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站油额,受9級特大地震影響叠纷,放射性物質發(fā)生泄漏。R本人自食惡果不足惜潦嘶,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一涩嚣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧衬以,春花似錦缓艳、人聲如沸校摩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽衙吩。三九已至互妓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冯勉。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工澈蚌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灼狰。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓宛瞄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親交胚。 傳聞我的和親對象是個殘疾皇子份汗,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內容