1. 程式人生 > >以登入註冊理解Cookie的作用過程

以登入註冊理解Cookie的作用過程

完整程式碼:

完整程式碼

Cookie在註冊登入時的作用過程:

註冊

註冊時把賬號密碼寫入資料庫

登入

第一次登入時伺服器給瀏覽器傳送Cookie.

後臺的登入路由程式碼(nodejs):

else if (path === '/sign_in' && method === 'POST') {
        readBody(request).then((body) => {
            let strings = body.split('&') // ['email=1', 'password=2', 'password_confirmation=3']
            let hash = {}
            strings.forEach((string) => {
                // string == 'email=1'
                let parts = string.split('=') // ['email', '1']
                let key = parts[0]
                let value = parts[1]
                hash[key] = decodeURIComponent(value) // hash['email'] = '1'
            })
            let {
                email,
                password
            } = hash
            var users = fs.readFileSync('./db/users', 'utf8')
            try {
                users = JSON.parse(users) // []
            } catch (exception) {
                users = []
            }
            let found
            for (let i = 0; i < users.length; i++) {
                if (users[i].email === email && users[i].password === password) {
                    found = true
                    break
                }
            }
            if (found) {//關鍵在這裡,驗證成功,設定登入Cookie為登入的郵箱,並放在響應裡發給瀏覽器
                response.setHeader('Set-Cookie', `sign_in_email=${email}`)
                response.statusCode = 200
            } else {
                response.statusCode = 401
            }
            response.end()
        })
    }

在登入成功的一瞬間,需要後臺設定一個Cookie,記錄一下登陸的使用者id(這裡用郵箱表示,程式碼在上面),然後發響應給瀏覽器例如在伺服器端設定響應頭:set-cookies:[email protected]

這時候我們檢視響應:

clipboard.png

發現響應頭已經設定cookie.

clipboard.png

然後跳轉到主頁,這時候我們檢視跳轉到主頁的請求:

clipboard.png

發現跳轉到主頁的請求頭中包含cookie欄位(以後訪問這個域名都會帶著這個Cookie)!所以,就像上篇文章說的:

如果伺服器給了瀏覽器一個setcookie的響應頭,那麼這個瀏覽器以後所有的請求,只要是相同的源(即就是上次給我傳送Cookie的那個域名,域名和埠相同),那就麼就會把當時伺服器發給這個瀏覽器的Cookie帶著

以後,瀏覽器一旦訪問這個路徑,瀏覽器就會附上這段 Cookie 傳送給伺服器

即:第一次請求,伺服器為瀏覽器設定Cookie.下次請求,瀏覽器帶上Cookie,傳送給伺服器.第一次登入的時候,伺服器給瀏覽器的響應設定一個Cookie,set-cookies:[email protected],然後當瀏覽器下次進行請求的時候,發現Cookie中有名為User_email的Cookie,而且我傳送請求的域名還是上次發給我帶Cookie的響應的那個域名.

那麼就無需再次登入了.相當於伺服器給瀏覽器發了進入門票,下次或下下次瀏覽器在進入伺服器的時候給伺服器看票就可以了

後臺讀取Cookie保留登入狀態與刪除Cookie退出登入狀態

首頁程式碼:

<body>
    <h1>我是首頁</h1>
    <div class="">
        <a href="./sign_up">註冊</a>
        <a href="./sign_in">登入</a>
    </div>
    
    <h1>你的狀態是:__status__</h1>
    <h1>你的郵箱賬號是:__email__</h1>
    <h1>你的密碼是:__password__</h1>

    <a href="javascript:;" id="logOffBtn">退出登入(刪除cookie)</a>

</body>
<script>
logOffBtn.addEventListener("click", () => {
        // 刪除一個現存 Cookie 的唯一方法,是設定它的expires屬性為一個過去的日期。
        document.cookie = 'sign_in_email=;expires=Thu, 01-Jan-1970 00:00:01 GMT'
        window.location = "/"
    })
</script>

後臺路由程式碼

if (path === '/') {
        response.statusCode = 200
        let string = fs.readFileSync('./index.html')
        string = string.toString();
        var users = fs.readFileSync('./db/users', 'utf8')
        users = JSON.parse(users)//轉化為user物件陣列

        console.log(users);
        let cookies = request.headers.cookie || ''//['email=111', 'asdasd=111']
        cookies = cookies.split("; ")
        let hash={}
        cookies.forEach((string)=>{
            let parts = string.split("=")
            let key = parts[0]
            let value = parts[1]
            hash[key] = value;
        })
        
        let eamil = hash.sign_in_email
        let foundedUser
        users.forEach((userObj)=>{
            if(userObj.email===eamil){
                foundedUser = userObj;
            }
        })
        console.log(foundedUser);
        if(foundedUser){
            string = string.replace('__status__', '已登入')
            string = string.replace('__email__', foundedUser.email)
            string = string.replace('__password__', foundedUser.password)
        }else{
            string = string.replace('__status__', '未登入,請去登入')
            string = string.replace('__email__', '沒')
            string = string.replace('__password__', '沒')
        }
        
        response.setHeader('Content-Type', 'text/html;charset=utf-8')
        response.write(string)
        response.end()
    }

在沒有Cookie的時候,首頁的狀態

clipboard.png

登入之後,後臺根據Cookie查詢資料庫,將使用者名稱與密碼傳到前臺的首頁上

clipboard.png

退出登入將刪除Cookie並重新整理頁面,重新回到未登入的狀態

Cookie在登入的時候的特點

我們得到Cookie的特點:

  1. 第一次登入的時候,伺服器通過 Set-Cookie 響應頭設定 Cookie,然後以響應的形式發給瀏覽器
  2. 瀏覽器得到 響應中Cookie 之後,之後每次請求這個域名都要帶上這個 Cookie
  3. 之後伺服器讀取當時自己設定的 Cookie 就知道登入使用者的資訊(email)

幾個關於Cookie的問題

1.我在 Chrome 登入了得到 Cookie,用 Safari 訪問,Safari 會帶上 Cookie 嗎no

2.Cookie 存在哪Windows 存在 C 盤的一個檔案裡

3.Cookie會被使用者篡改嗎?可以,例如在谷歌瀏覽器開發者模式下的application->Cookie中可以手動修改,修改之後,下次傳送請求時,附帶的就是修改後的Cookie

修改Cookie

JS中也有可以操作cookie的api( 假如換成別的使用者的賬號,那麼還可以登入成功的話,就會存在風險問題.Session 來解決這個問題,防止使用者篡改)後端可以強制設定不允許修改Cookie,只要將Cookie的屬性設定為Httponly即可(還可以手動改,但是JS改不了,也無法獲取),具體語法看 MDN4.Cookie 有效期嗎?預設有效期20分鐘左右,不同瀏覽器策略不同(如果瀏覽器一直開著,那麼Cookie不會被刪除.如果關閉瀏覽器,那麼瀏覽器為了安全考慮,20分鐘左右後可能會刪除Cookie.這也取決於伺服器如何設定Cookie的有效期)後端可以強制設定有效期,具體語法看 MDNCookie 遵守同源策略嗎?也有,不過跟 AJAX 的同源策略稍微有些不同。當請求 qq.com 下的資源時,瀏覽器會預設帶上 qq.com 對應的 Cookie,不會帶上 baidu.com 對應的 Cookie當請求 v.qq.com 下的資源時,瀏覽器不僅會帶上 v.qq.com 的Cookie,還會帶上 qq.com 的 Cookie另外 Cookie 還可以根據路徑做限制,請自行了解,這個功能用得比較少。

需要注意的細節問題

為什麼前後端都要進行表單驗證?

前後端都要驗證郵箱格式是否正確,賬號密碼格式是否正確,兩次提交的密碼是否相同等。因為黑客可以繞過前端的js驗證流程,例如黑客可以直接使用curl 進行請求的傳送,直接與後臺伺服器進行互動。如圖:

clipboard.png

所以後臺也需要進行表單驗證。

Cookie如何手動關閉

clipboard.png

翻譯

cookie:曲奇餅cache-control:快取控制