天天看點

會話身份驗證 vs 令牌身份驗證:哪個更好?

作者:不秃頭程式員
會話身份驗證 vs 令牌身份驗證:哪個更好?

在本文中,我們将了解後端應用程式中使用的基于會話和令牌的身份驗證方法。

基于會話的身份驗證

簡單講,基于會話(Session)的身份驗證使用存儲在裝置上的特殊代碼(Session ID)來記住你通路網站時的身份,保持登入狀态并記住你的資訊,直到你離開或登出。

還沒明白嗎?别着急,我們一步一步來看。

1. 使用者登入:

使用者通過特殊請求通過郵箱和密碼發送到伺服器來登入。

2. 檢查詳情:

伺服器檢查提供的詳細資訊是否與為使用者存儲的資訊比對。

3. 建立會話:

如果一切正确,伺服器将建立一個儲存使用者資訊(如User ID、權限和時間限制)的“Session”。此資訊安全地儲存在伺服器的存儲中,名字可以使用諸如express-session。

4. 擷取會話ID:

伺服器将此“會話 ID”發送回使用者的裝置,通常作為響應中的Cookie。

5. 使用會話 ID:

每當使用者想要從伺服器擷取某些内容時,他們的裝置會自動在其請求中包含此會話 ID。

6. 伺服器檢查:

伺服器使用此會話 ID 來查找會話存儲中存儲的有關會話使用者的資訊。

以下是express-session工作原理:

  • 當使用者登入時,伺服器會為該使用者建立一個會話,并在包含會話 ID 的響應中設定一個 cookie。
  • 浏覽器會自動在向伺服器發出的後續請求中包含此會話 ID cookie。
  • 當伺服器收到請求時,express-session 中間件使用 cookie 中的會話 ID 來檢索相關會話資料。
  • 存儲在req.session中的資料(例如 userId)可用于處理請求。

7. 授予通路權限:

如果一切全都比對,伺服器就知道使用者是真實的,并響應他們所請求的内容。

會話身份驗證 vs 令牌身份驗證:哪個更好?

代碼例子

下面是一個使用 Express.js 實作會話身份驗證的 Node.js 應用程式的示例。

const express = require('express');

const session = require('express-session');

const app = express();

// 中間件設定
app.use(session({
  secret: 'your_secret_key',
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true, // Set the cookie as HTTP-only, Optional
    maxAge: 60*30 // In secs, Optional
  }
}));


//登入

app.post('/login', (req, res) => {
  const { username, password } = req.body;
  const user = users.find(u => u.username === username && u.password === password);

  if (user) {
    req.session.userId = user.id; // Store user ID in session
    res.send('Login successful');
  } else {
    res.status(401).send('Invalid credentials');
  }
});
//受保護頁面
app.get('/home', (req, res) => {
  if (req.session.userId) {
    // User is authenticated
    res.send(`歡迎您光臨,${req.session.userId}!`);
  } else {
    // User is not authenticated
    res.status(401).send('Unauthorized');
  }
});
//登出
app.get('/logout', (req, res) => {
  req.session.destroy(err => {
    if (err) {
      res.status(500).send('登出出現錯誤');
    } else {
      res.redirect('/'); // Redirect to the home page after logout
    }
  });
});           

基于令牌的身份驗證

JWT 身份驗證使用包含使用者資訊的數字簽名令牌(Token),其允許對網站或應用程式進行安全且經過驗證的通路,而無需重複登入。

讓我們看一下基于令牌的身份驗證的分步工作流程。

1. 使用者登入請求:

使用者通過特定請求将電子郵件和密碼發送到伺服器來登入。

2. 憑證驗證:

伺服器根據存儲的使用者資料驗證提供的憑據。

3. 代币生成:

驗證成功後,伺服器會建立一個令牌(通常為 JWT - JSON Web 令牌)。該令牌儲存使用者資訊(聲明),例如 user_id、權限。

4. 令牌簽名與哈希:

該令牌使用密鑰進行簽名,并使用雜湊演算法(如 SHA256)進行處理以建立散列。

5. 發送令牌:

伺服器将此令牌發送到用戶端,用戶端通常将其存儲在浏覽器中。

6. 代币存儲選項:

用戶端可以以不同的方式存儲令牌,例如 HttpOnly Cookie、會話存儲或本地存儲。建議存儲在 HttpOnly Cookies 中,因為它可以防止 JavaScript 通路,進而增強針對 XSS 攻擊的安全性。

7. 令牌到期和安全:

令牌通常有一個過期時間以增強安全性。

8. 在請求中包含 Token:

對于向伺服器發出的每個請求,用戶端都會在授權标頭中發送令牌。

最好在令牌前加上“Bearer”字首。

axios.get(URL, {
    headers: {
        'Authorization': 'Bearer ' + token,
    },
})           

9. 伺服器端驗證:

收到請求後,伺服器檢索令牌。

10. 令牌驗證和使用者認證:

使用密鑰,伺服器驗證令牌并從中提取聲明。如果聲明中的使用者資訊存在于伺服器的使用者表中,則伺服器會對使用者進行身份驗證,并授予對所請求資源的通路權限。

會話身份驗證 vs 令牌身份驗證:哪個更好?

代碼例子

//登入
app.post('/login', (req, res) => {

const { username, password } = req.body;
  const user = users.find(u => u.username === username && u.password === password);

  jwt.sign({ user }, secretKey, { expiresIn: '1h' }, (err, token) => {
    if (err) {
      res.status(500).send('Error generating token');
    } else {
      res.json({ token });
    }
  });
});           

處理保護頁面

我們使用veriyToken()函數作為中間件來處理每條需要驗證的路由。請求通過,veriyToken()并且僅當next()調用該函數時,它才會傳遞到該路由并實作代碼。

app.get('/dashboard', verifyToken, (req, res) => {
  res.send('Welcome to the Home page');
});

// Verify token middleware
function verifyToken(req, res, next) {
  const token = req.headers['authorization'];

  if (typeof token !== 'undefined') {
    jwt.verify(token.split(' ')[1], secretKey, (err, decoded) => {
      if (err) {
        res.status(403).send('Invalid token');
      } else {
        req.user = decoded.user;
        next();
      }
    });
  } else {
    res.status(401).send('Unauthorized');
  }
}           

兩種方法的差異

  • 存儲位置:會話存儲在伺服器上,而令牌(JWT)存儲在用戶端。
  • 有狀态與無狀态:會話是有狀态的,而令牌是無狀态的,進而可以在分布式系統中實作更好的可擴充性。
  • 過期處理:會話過期由伺服器管理,而令牌過期由令牌本身處理。
  • 安全措施:JWT 通常包括數字簽名和加密支援,與使用 cookie 的典型會話機制相比增強了安全性,并且如果保護不當,可能容易受到 CSRF 攻擊。
  • 使用靈活性:令牌 (JWT) 在攜帶身份驗證之外的附加資訊方面提供了更大的靈活性,對于授權和自定義資料傳輸非常有用。

應該使用哪種方法?

這取決于應用程式的要求和性質。大多數應用程式會使用混合方法,即針對 API 的基于令牌的身份驗證,以及針對基于 Web 的互動的基于會話的身份驗證。