作了四年的前端開發,對外一直說本身是web開發,那麼身爲一個web開發怎能不知道session與cookie以及其管理方式呢~javascript
Login涉及技術棧:Nodejs,MongoDB,Express以及html,css,jscss
瞭解session與cookie以前首先要知道什麼是http協議,爲何會出現session與cookie,能夠參考好久以前總結的(戳我:session與cookie)。html
http即超文本傳輸協議(萬維網定義的),一種基於瀏覽器請求與服務器響應的連接,它是一個很純粹的傳輸協議。http協議主要的特徵就是它是一種無狀態的協議(只針對cookie與session問題),在客戶端連續向服務器發送請求的時候,每次請求的過程當中只要數據交換完畢,服務器與客戶端就會斷開鏈接,再次請求的時候會從新鏈接客戶端與服務器,這樣服務器記錄上次的對話,那麼問題來了,如何讓服務器知道是哪一個客戶端向本身發出的請求呢,這個時候cookie就誕生了~前端
cookie是一小段文本信息,這段小文本信息由服務器首次響應客戶端時發送的,在客戶端向服務器首次發送請求的時候,服務器會判斷是否要記錄客戶端的身份,若是須要,此時就會在響應中(response)給客戶端發送一個cookie,該cookie文本信息保存在http的報頭裏,當瀏覽器會將cookie保存起來,當該瀏覽器再次發送請求時會攜帶cookie,服務器檢查cookie來識別瀏覽器請求,這裏cookie的特徵就不在說明了。下面咱們上代碼!java
頁面代碼:jquery
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <script type="text/javascript" src="jquery-3.3.1.min.js"></script> <script type="text/javascript" src='test.js'></script> </head> <body> <section> <h3>Register</h3> <div> <label style="display:inline-block; width: 100px;" id="register-user-name-label" htmlfor="register-user-name-input">register:</label> <input style="display:inline-block; width: 200px;" id="register-user-name-input" type="text" /> </div> <div> <label style="display:inline-block; width: 100px;" id="register-password-label" htmlfor="register-password-input">pasword:</label> <input style="display:inline-block; width: 200px;" id="register-password-input" type="text" /> </div> <button id="register" type="button">Register</button> </section> <section> <h3>Login</h3> <div> <label style="display:inline-block; width: 100px;" id="user-name-label" htmlfor="user-name-input">login name:</label> <input style="display:inline-block; width: 200px;" id="user-name-input" type="text" /> </div> <div> <label style="display:inline-block; width: 100px;" id="password-label" htmlfor="password-input">pasword:</label> <input style="display:inline-block; width: 200px;" id="password-input" type="text" /> </div> <button id="login" type="button">Login</button> </section> <script type="text/javascript" src='test.js'></script> </body> </html>
很簡單,一個註冊按鈕一個登錄按鈕(ps:代碼冗餘請忽視,就是爲了作個demo用)。git
首先註冊一個user:github
註冊user以後咱們查看dbweb
而後咱們用這個user進行登錄操做,重點來啦~redis
首先刷新下頁面,調用獲取user方法,看下效果
代碼以下:
app.get('/userInfo', function (req, res) { //cookie if (req.cookies.userInfo) { console.log('login successfully') } else { console.log('session timeout.'); } res.status(200).json(req.cookies.userInfo); //session // if (req.session.userInfo) console.log('login successfully'); // else console.log('session timeout.'); })
好了先mark下,回頭再來作對比,下面執行login操做,這裏要上代碼了。
首先引入一箇中間件:
var cookie = require('cookie-parser');
使用它:
app.use(cookie('express_cookie')); //cookie app.post('/login', function (req, res) { User.findOne({ username: req.body.username }).then(function (userInfo) { if (!userInfo) { console.log('user is not exist.'); return; } var data = {}; data['username'] = userInfo.username; data['password'] = userInfo.password; res.cookie('username', JSON.stringify(data), { maxAge: 900000, httpOnly: true }); res.status(200).json(data); }) .catch(function (e) { console.log(e); }) })
這裏咱們能夠設置cookie的httpOnly屬性,最大生命週期,等等,而後咱們先在db內查詢當前登陸user,若是已經註冊過,咱們獲取user信息並存入cookie中。這時候看下前端的響應有什麼不一樣。
能夠看見,服務器頒發的cookie在響應的header中的Set-Cookie中。似不似發現不一樣了。這時候咱們在刷新下頁面調用userInfo方法看下效果。
咦,咱們發現此次的請求裏面竟然有cookie了,就這麼神奇(Ps:咱們要相信科學!)。
debug下看看
服務器端有咱們想要的cookie信息了。這樣服務器就能夠根據cookie知道了咱們每一次的請求是否是同一我的了。
總結:首先cookie是服務器頒發的,而後隨着響應返回給客戶端也就是咱們的瀏覽器,瀏覽器保存cookie,每一次發送請求都會帶着這個cookie來讓服務器知道,嗯我就是上次的那我的,到這裏對cookie是否是多少了解了一些呢~
好了,那麼如今不少瀏覽器都是禁用cookie的,緣由是啥呢~,因爲cookie是能夠被獲取的以及cookie是能夠修改的,這時候引出了web安全方面的姿式,跨站腳本攻擊以及跨站協議僞造,能夠參考我以前寫的關於XSS攻擊(戳我:什麼是XSS以及CFRS),那麼若是cookie禁用了咱們該怎麼辦呢?這時候session就誕生了。
session本省並不存在,只是一個概念,session是服務器用來記錄客戶端狀態的機制,不一樣於cookie保存在瀏覽器中,session是保存在服務器上的,服務器會根據cookie生成一個session id存在服務器上,當請求再次抵達服務器時,服務器發出響應時會將session id 存在cookie內一同反回給瀏覽器,這就是session。session具體哪些特色這裏就不寫啦,話很少說,上代碼。
首先引入一箇中間件:
var session = require('express-session');
使用它
app.use(cookie('express_cookie')); app.use(session({ secret: 'express_cookie', resave: false, saveUninitialized: true, cookie: { maxAge: 60 * 1000 * 30 }, rolling: true, })); app.post('/login', function (req, res) { User.findOne({ username: req.body.username }).then(function (userInfo) { if (!userInfo) { console.log('user is not exist.'); return; } var data = {}; data['username'] = userInfo.username; data['password'] = userInfo.password; req.session.userInfo = data; res.status(200).json(data); }) .catch(function (e) { console.log(e); }) })
如今咱們登陸一下看下效果:
會發現,多了一個Cookie,並且Cookie裏面多了一個sid,不用聯想了,這就是sessionId,這時候咱們在刷新一下頁面看下userInfo變成啥樣了呢?
能夠清晰的看到再次請求的時候,sessionId會裝在Cookie中,而後發送給服務器,這時候服務器就知道了,咦,原來是上我的。這就是session。
因爲如今服務器session存入的方式咱們採用了服務器自帶的內存,也叫session memory。若是server掛了怎麼辦呢,掛掉了內存就釋放了啊,session就沒了啊。這個時候就引出了另一個問題,session的可持續化。
session的可持續化方式簡單的理解就是讓session能夠在生命週期內一直存在,能夠把session存入db中,能夠是MongoDB,能夠是redis,上代碼,咱們這裏用MongoDB吧,我的比較喜好。
引入中間件:
var MongoStore = require('connect-mongo')(session);
app.use(cookie('express_cookie')); app.use(session({ secret: 'express_cookie', resave: false, saveUninitialized: true, cookie: { maxAge: 60 * 1000 * 30 }, rolling: true, store: new MongoStore({ url: 'mongodb://127.0.0.1:27017/demo', collection: 'sessions' }) })); app.post('/login', function (req, res) { User.findOne({ username: req.body.username }).then(function (userInfo) { if (!userInfo) { console.log('user is not exist.'); return; } var data = {}; data['username'] = userInfo.username; data['password'] = userInfo.password; req.session.userInfo = data; res.status(200).json(data); }) .catch(function (e) { console.log(e); }) })
http請求與響應部分咱們就不看了,直接看server跟DB。
server中咱們將userInfo放入session中
var data = {}; data['username'] = userInfo.username; data['password'] = userInfo.password; req.session.userInfo = data;
查看DB
咦,一條session就在DB中誕生了,這裏要注意的是,session不是設置的時候就會存入DB中的,包括內存等等,並且響應成功的時候纔會存入,必定要注意,否則坑的就是你。
而後刷新頁面看下效果。
似不似,session中就有了user信息。好了到這裏關於session持久化的問題也解決了。
登出功能就很簡單了,銷燬session就ok了,代碼以下:
app.get("/loginOut",function(req,res){ req.session.destroy(function(err){ console.log(err); }) res.send('退出登陸成功'); });
Redis方式:
中間件以及使用:
var RedisStrore = require('connect-redis')(session); app.use(session({ secret: 'express_cookie', resave: false, saveUninitialized: true, cookie: { maxAge: 60 * 1000 * 30 }, rolling: true, store: new RedisStrore({}) }));
總結:第一次登錄請求的時候,服務器會頒發一個sessionId,響應的時候將sessionId放入cookie中返回給瀏覽器,此時session已存入DB中,當再次請求的時候攜帶着sessionId進入服務器中,獲取session信息,服務器仍是會記得我。
時間不早了。在這塊的知識還涉及何時token,token認證方式,以及什麼是jwt。之後有時間會繼續更新的。
代碼地址:https://github.com/Dqhan/Login
大半夜的,寫個博客不容易,請博客園管理員高擡貴手,讓我留在首頁吧。