token 和 cookie 还在傻傻分不清?

token 概念和作用

Token是一种用于身份验证和授权的令牌。在Web应用程序中,当用户进行登录或授权时,服务器会生成一个Token并将其发送给客户端。客户端在后续的请求中将Token作为身份凭证携带,以证明自己的身份。

Token可以是一个字符串,通常是经过加密和签名的,以确保其安全性和完整性。服务器收到Token后,会对其进行解析和验证,以验证用户的身份并授权对特定资源的访问权限。

Token的使用具有以下特点:

  • 无状态:服务器不需要在数据库中存储会话信息,所有必要的信息都包含在Token中。
  • 可扩展性:Token可以存储更多的用户信息,甚至可以包含自定义的数据。
  • 安全性:Token可以使用加密算法进行签名,以确保数据的完整性和安全性。
  • 跨域支持:Token可以在跨域请求中通过在请求头中添加Authorization字段进行传递。

Token在前后端分离的架构中广泛应用,特别是在RESTful API的身份验证中常见。它比传统的基于Cookie的会话管理更灵活,并且适用于各种不同的客户端,例如Web、移动应用和第三方接入等。

Cookie和Token是两种不同的概念,但它们在身份验证和授权方面可以有关联。

Cookie是服务器在HTTP响应中通过Set-Cookie标头发送给客户端的一小段数据。客户端浏览器将Cookie保存在本地,然后在每次对该服务器的后续请求中将Cookie作为HTTP请求的一部分发送回服务器。Cookie通常用于在客户端和服务器之间维护会话状态,以及存储用户相关的信息。

Token是一种用于身份验证和授权的令牌。它是一个包含用户身份信息的字符串,通常是服务器生成并返回给客户端。客户端在后续的请求中将Token作为身份凭证发送给服务器,服务器通过验证Token的有效性来确认用户的身份和权限。

Cookie和Token可以结合使用来实现身份验证和授权机制。服务器可以将Token存储在Cookie中,然后发送给客户端保存。客户端在后续的请求中将Token作为Cookie发送给服务器。服务器通过验证Token的有效性来判断用户的身份和权限。这种方式称为基于Cookie的身份验证。另外,也可以将Token直接存储在请求的标头中,而不是在Cookie中进行传输,这种方式称为基于Token的身份验证。

需要注意的是,Token相对于Cookie来说更加灵活和安全,可以实现跨域身份验证,以及客户端和服务器的完全分离。而Cookie则受到一些限制,如跨域访问限制,以及容易受到XSS和CSRF攻击等。因此,在实现身份验证和授权机制时,可以选择使用Token替代或辅助Cookie。

token 一般在客户端存在哪儿

Token一般在客户端存在以下几个地方:

  • Cookie:Token可以存储在客户端的Cookie中。服务器在响应请求时,可以将Token作为一个Cookie发送给客户端,客户端在后续的请求中会自动将Token包含在请求的Cookie中发送给服务器。
  • Local Storage/Session Storage:Token也可以存储在客户端的Local Storage或Session Storage中。这些是HTML5提供的客户端存储机制,可以在浏览器中长期保存数据。
  • Web Storage API:除了Local Storage和Session Storage,Token也可以使用Web Storage API中的其他存储机制,比如IndexedDB、WebSQL等。
  • 请求头:Token也可以包含在客户端发送的请求头中,一般是在Authorization头中携带Token。

需要注意的是,无论将Token存储在哪个地方,都需要采取相应的安全措施,如HTTPS传输、加密存储等,以保护Token的安全性。

存放在Cookie中相对来说是比较常见的做法,但是并不是最安全的方式。存放在Cookie中的Token可能存在以下安全风险:

  • 跨站脚本攻击(XSS) :如果网站存在XSS漏洞,攻击者可以通过注入恶意脚本来获取用户的Cookie信息,包括Token。攻击者可以利用Token冒充用户进行恶意操作。
  • 跨站请求伪造(CSRF) :攻击者可以利用CSRF漏洞,诱使用户在已经登录的情况下访问恶意网站,该网站可能利用用户的Token发起伪造的请求,从而执行未经授权的操作。
  • 不可控的访问权限:将Token存放在Cookie中,意味着浏览器在每次请求中都会自动携带该Token。如果用户在使用公共计算机或共享设备时忘记退出登录,那么其他人可以通过使用同一个浏览器来访问用户的账户。

为了增加Token的安全性,可以采取以下措施:

  • 使用HttpOnly标识:将Cookie设置为HttpOnly,可以防止XSS攻击者通过脚本访问Cookie。
  • 使用Secure标识:将Cookie设置为Secure,只能在通过HTTPS协议传输时发送给服务器,避免明文传输。
  • 设置Token的过期时间:可以设置Token的过期时间,使得Token在一定时间后失效,减少被滥用的风险。
  • 使用其他存储方式:考虑将Token存储在其他地方,如Local Storage或Session Storage,并采取加密等额外的安全措施保护Token的安全性。

token 身份验证代码实现

服务端使用 JWT 进行 token 签名和下发

可以参考使用这个库 node-jsonwebtoken

后端代码示例 (Node.js / Express),代码简单实现如下:

javascript 复制代码
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

const secretKey = 'mysecretkey';

app.use(express.json());

app.post('/api/login', (req, res) => {
  // 从请求中获取用户名和密码
  const { username, password } = req.body;

  // 验证用户名和密码
  if (username === 'admin' && password === 'password') {
    // 用户名和密码验证成功,生成Token并返回给前端
    const token = jwt.sign({ username }, secretKey, { expiresIn: '1h' });
    res.json({ token });
  } else {
    // 用户名和密码验证失败,返回错误信息给前端
    res.status(401).json({ error: 'Authentication failed' });
  }
});

app.get('/api/protected', verifyToken, (req, res) => {
  // Token验证成功,可以访问受保护的路由
  res.json({ message: 'Protected API endpoint' });
});

function verifyToken(req, res, next) {
  const token = req.headers.authorization;

  if (!token) {
    return res.status(401).json({ error: 'Missing token' });
  }

  // 验证Token
  jwt.verify(token, secretKey, (err, decoded) => {
    if (err) {
      return res.status(401).json({ error: 'Invalid token' });
    }

    // Token验证通过,将解码后的数据存储在请求中,以便后续使用
    req.user = decoded;
    next();
  });
}

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

在上述后端代码中,我们使用了jsonwebtoken库来生成和验证Token。在登录路由/api/login中,验证用户名和密码成功后,生成一个Token并返回给前端。在受保护的路由/api/protected中,我们使用verifyToken中间件来验证请求中的Token,只有通过验证的请求才能访问该路由。

当然实际开发中, 可以使用中间件来进行 jwt 的验证, 下发方式也因人而异, 可以放在 cookie 中, 也可以作为 response 返回均可, 上述代码仅作参考;

前端代码实现示范如下

前端获取到了Token后将其存储在Cookie中,并在后续请求中自动发送给后端,可以通过以下方式实现前端代码:

jsx 复制代码
import React, { useState, useEffect } from 'react';

function App() {
  const [token, setToken] = useState('');

  useEffect(() => {
    // 检查本地是否有保存的Token
    const savedToken = localStorage.getItem('token');
    if (savedToken) {
      setToken(savedToken);
    }
  }, []);

  const handleLogin = async () => {
    // 发送请求到后端进行登录验证
    const response = await fetch('http://example.com/api/login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ username: 'admin', password: 'password' }),
    });

    if (response.ok) {
      // 登录成功,获取Token并保存到前端
      const data = await response.json();
      setToken(data.token);
      // 保存Token到本地
      localStorage.setItem('token', data.token);
    }
  };

  const handleLogout = () => {
    // 清除保存的Token
    setToken('');
    // 清除本地保存的Token
    localStorage.removeItem('token');
  };

  return (
    <div>
      {token ? (
        <div>
          <p>Token: {token}</p>
          <button onClick={handleLogout}>Logout</button>
        </div>
      ) : (
        <button onClick={handleLogin}>Login</button>
      )}
    </div>
  );
}

export default App;
相关推荐
匹马夕阳2 分钟前
Vue 3中导航守卫(Navigation Guard)结合Axios实现token认证机制
前端·javascript·vue.js
你熬夜了吗?4 分钟前
日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件
前端·vue.js·信息可视化
DogDaoDao5 小时前
leetcode 面试经典 150 题:有效的括号
c++·算法·leetcode·面试··stack·有效的括号
桂月二二6 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062067 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb8 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角8 小时前
CSS 颜色
前端·css
九酒8 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔9 小时前
HTML5 新表单属性详解
前端·html·html5
lee5769 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm