很多开发者刚开始做项目时都会遇到这个问题:用户登录后拿到的token,到底应该存在哪里?LocalStorage、SessionStorage、Cookie,还是直接放在内存中?为什么不同的网站做法不一样?
这个问题确实让人困惑。每次看到不同项目使用不同的存储方式,很多人都会想:到底哪种方法才是正确的?
想象一下,你家的钥匙你会放在哪里?随身带着?藏在门垫下面?还是交给保安保管?如果放错了地方,小偷就可能进你家门。
token就是用户进入系统的钥匙。如果存错了地方,黑客就能冒充用户登录账号,后果很严重。
永久保存,除非手动删除
同一个网站的任何页面都能读取
刷新页面或关闭浏览器都不会丢失
如果网站有安全漏洞,token可能被偷
需要手动添加到请求头中
只在当前浏览器标签页有效
同一个网站可以读取
适合临时操作
关闭浏览器标签页就消失
同样有安全风险
需要手动管理
可以设置过期时间
可以设置HttpOnly(JavaScript读不到)
可以设置Secure(只通过HTTPS传输)
可以设置SameSite(防止某些攻击)
自动随着请求发送
容量有限制(约4KB)
每次请求都会携带,可能浪费流量
页面刷新就丢失
完全由前端控制,不持久保存
最快最安全,但生命周期最短
不适合需要持久保存的情况
关闭标签页就没了
很多前端开发者的第一反应是:"用LocalStorage最方便!"
确实,几行代码就能搞定:
// 保存token
localStorage.setItem('token', res.token);
// 发送请求时使用
axios.defaults.headers.common['Authorization'] = localStorage.getItem('token');
方便是真的方便,但安全问题也需要考虑。
安全例子: 如果网站有个评论区,用户输入的内容没有做安全检查,黑客可能插入这样的代码:
<script>
fetch('/steal?token=' + localStorage.getItem('token'))
</script>
用户打开页面时,这段代码执行,你的token就被发送到黑客的服务器了。
如果token存在HttpOnly Cookie里,JavaScript读不到,这种攻击就失效了。
也不是。Cookie也有自己的问题。比如黑客可能诱导你访问一个恶意页面:
<img src="https://yourbank.com/transfer?to=hacker&amount=100000" />
如果你的登录信息在Cookie里,浏览器会自动带上Cookie,请求就可能成功。用户什么都没做,钱可能就被转走了。
这是目前大多数新项目采用的方式。
技术组合:
部署方式:
用户浏览器访问前端网站,前端通过API与后端通信。
登录流程:
用户登录
后端验证用户名密码,生成JWT
返回给前端:{ token: "xxxxxx" }
前端存入localStorage
后续请求时,前端手动添加请求头:
axios.defaults.headers.common['Authorization'] = 'Bearer ' + token
后端解析JWT,验证身份
优点:
前后端完全分开,各自独立开发部署
适合现代架构
开发简单,调试方便
缺点:
有安全风险
需要手动管理token
跨域配置稍麻烦
适合场景:
后台管理系统
普通网站、商城
需要快速上线的项目
这是目前最主流的方案,大部分新项目都这样用。
把前端代码打包后放到后端的静态资源目录里,由后端统一提供页面和API。
访问方式:
页面:http://localhost:8080/
API:http://localhost:8080/api/xxx
优点:
部署简单
没有跨域问题
适合小型项目
缺点:
前后端耦合,不利于独立更新
静态资源由后端服务提供,性能可能不如专用服务器
不适合高并发场景
适合场景:
内部工具
学习项目
对性能要求不高的系统
这种方案在企业级项目中逐渐减少,但在小项目中仍然常见。
这是银行、金融等高安全性系统中常用的专业做法。
方案核心:
access_token:短期JWT,存在前端内存,用于API认证
refresh_token:长期token,存在HttpOnly Cookie,用于刷新access_token
流程:
登录成功
后端:设置HttpOnly Cookie存储refresh_token
响应体:返回access_token
前端:
存access_token到内存
请求时添加Authorization头
access_token过期后:
调用刷新接口
浏览器自动携带refresh_token
获取新的access_token
优点:
安全性高
即使access_token泄露,有效期也很短
极高的安全性
缺点:
实现复杂
需要后端配合
要处理好刷新机制
适合场景:
银行、支付系统
高权限后台
对安全要求极高的系统
使用Spring Security + Session,登录后设置HttpOnly的Session Cookie。
前端不需要处理token,浏览器会自动携带Cookie。
优点:
安全性高
后端可以管理session
适合内部系统
缺点:
需要处理跨站请求伪造问题
不适合现代架构
跨域配置复杂
适合场景:
传统企业系统
内部管理系统
已有相关架构的项目
方案 | 安全性 | 易用性 | 推荐度 | 适用场景 |
---|---|---|---|---|
前后端分离 + JWT + LocalStorage | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 90%的新项目 |
前后端合并部署 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | 小项目、学习 |
双Token机制 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | 高安全系统 |
Cookie + Session | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | 传统企业系统 |
如果你是新手或做小项目:用前后端分离 + JWT + localStorage,简单直接
如果你做后台系统或普通网站:同上,但要做好安全防护(输入检查、安全策略等)
如果你做金融或高权限系统:用双Token机制,安全第一
如果你是传统企业或内部系统:可以考虑Cookie + Session,但要配置好安全设置
目前Vue + SpringBoot的标准做法是:前后端分离 + JWT + LocalStorage。
虽然这种方案有安全风险,但因为开发效率高、架构清晰、适合现代部署等优势,已经成为主流。
安全问题不是单靠"不用localStorage"就能解决的,而是需要:
严格的输入验证
安全策略配置
定期安全检查
使用安全头部
技术选择,永远是在安全、效率、成本之间找到平衡。
// 登录后保存token
function loginSuccess(token) {
localStorage.setItem('auth_token', token);
}
// 发送请求时添加token
function apiRequest(url, data) {
const token = localStorage.getItem('auth_token');
return fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(data)
});
}
// 退出登录时清除
function logout() {
localStorage.removeItem('auth_token');
}
let accessToken = '';
// 登录处理
async function login(credentials) {
const response = await fetch('/api/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(credentials)
});
const data = await response.json();
accessToken = data.access_token;
// refresh_token会自动保存在HttpOnly Cookie中
}
// 自动刷新token
async function refreshToken() {
try {
const response = await fetch('/api/refresh', {
method: 'POST',
credentials: 'include' // 自动携带Cookie
});
const data = await response.json();
accessToken = data.access_token;
return true;
} catch (error) {
return false;
}
}
选择哪种方案,要根据你的具体需求和项目特点来决定。对于大多数项目来说,方案一就足够了,但要知道它的优缺点,并做好相应的安全措施。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
以前的开发模式是以MVC为主,但是随着互联网行业快速的发展逐渐的演变成了前后端分离,若项目中需要做登录的话,那么token成为前后端唯一的一个凭证。token即标志、记号的意思,在IT领域也叫作令牌。
JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位。如果这个 Token 在服务端持久化(比如存入数据库
最近遇到个需求:前端登录后,后端返回token和token有效时间,当token过期时要求用旧token去获取新的token,前端需要做到无痛刷新token,即请求刷新token时要做到用户无感知。
前端登录后,后端返回token和token有效时间段tokenExprieIn,当token过期时间到了,前端需要主动用旧token去获取一个新的token,做到用户无感知地去刷新token。
这篇文章写一下前后端分离下的登录解决方案,目前大多数都采用请求头携带 Token 的形式。首次登录时,后端服务器判断用户账号密码正确之后,根据用户id、用户名、定义好的秘钥、过期时间生成 token
第一次登录的时候,前端调后端的登陆接口,发送用户名和密码,后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token,前端拿到token,将token存储到localStorage和vuex中
页面长时间未操作,再刷新页面时,第一次弹出“token失效,请重新登录!”提示,然后跳转到登录页面,接下来又弹出了n个“Token已过期”的后端返回消息提示。当前页面初始化,有多个向后端查询系统参数的调用,代码如下:
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!