一個Login頁面全面瞭解session與cookie

  • 背景

作了四年的前端開發,對外一直說本身是web開發,那麼身爲一個web開發怎能不知道session與cookie以及其管理方式呢~javascript

Login涉及技術棧:Nodejs,MongoDB,Express以及html,css,jscss

瞭解session與cookie以前首先要知道什麼是http協議,爲何會出現session與cookie,能夠參考好久以前總結的(戳我:session與cookie)。html

  • http協議:

http即超文本傳輸協議(萬維網定義的),一種基於瀏覽器請求與服務器響應的連接,它是一個很純粹的傳輸協議。http協議主要的特徵就是它是一種無狀態的協議(只針對cookie與session問題),在客戶端連續向服務器發送請求的時候,每次請求的過程當中只要數據交換完畢,服務器與客戶端就會斷開鏈接,再次請求的時候會從新鏈接客戶端與服務器,這樣服務器記錄上次的對話,那麼問題來了,如何讓服務器知道是哪一個客戶端向本身發出的請求呢,這個時候cookie就誕生了~前端

  • 什麼是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本省並不存在,只是一個概念,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能夠在生命週期內一直存在,能夠把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

大半夜的,寫個博客不容易,請博客園管理員高擡貴手,讓我留在首頁吧。

相關文章
相關標籤/搜索