前端怎么存token_学长:说说你理解的 Token
前言
在学 Javaweb 的时候,我们就一直被强调 javaweb 中有四大作用域:pageContext域
,request域
,session域
和 application域
。
pageContext 域
里的变量只能在当前页面使用。request 域
中对象的有效范围是当前的请求范围。session 域
中对象的有效范围是当前的会话范围。application 域
中对象的有效范围是整个应用 active (活跃) 的范围。
了解基本概念后,我们可以知道若要进行网络通信,我们一般都要使用到 request
和 session
。request
只是在请求范围内有效,每次请求后数据就会自动销毁。但有时候我们有想要存储一些能够存储久的数据,例如登录信息
,用户信息
等,request域
是做不到的。
服务端的 session
和 客户端(浏览器)的 cookie
的性质很相似,例如他们都能存储一定期限的数据。如果说 cookie
是客户身上的“通行证”,那么 Session
就是多个“通行证”组成的“客户明细表”。「「从理论上讲,这两个内存间是联系不到一块的。但是由于这两者相似的性质, java
的 jsp
,spring
的 thymeleaf
模板就将他们关联了起来。让人们产生 session
和 cookie
是一致的错觉。」」 以 jsp
为例,jsp
其是一个特殊的 servlet
程序,虽然我们在里面编写的是 html
语句,但他实际上是会通过 servlet
的一些手段从而转变为前端页面。而 spring
的 thymeleaf
模板也用了这样的方式。因为 session
能够存储时间久的数据,故我们能够用 session
来存储 登录信息
和用户信息
等。
session/cookie 的弊端:
cookie
不是很安全,别人可以分析存放在本地的cookie
并进行cookie欺骗
。- 单个
cookie
在客户端的限制是3K
,就是说一个站点在客户端存放的cookie
不能超过3k
。 session
会在一定时间内保存在服务器上。当访问量增多,会占用服务器的性能。- 如果是在服务器集群下,或者跨域的服务导向架构,就要求
session域
中的数据共享,即每台服务器都能够读取session
。这个时候我们就只能将session
数据持久化,这是一个非常糟糕的办法。
更加重大的问题
如果用户在浏览器的设置里禁用了 cookie
;或者你的网站是使用前后分离的技术来实现。根本就无法简单的使用 session
了。一是由于浏览器中没了 cookie
,你的数据无法存储在浏览器上,二是前后端分离将其联系撕裂,单独设置服务端的 session
无法同步到 浏览器的 cookie
中。此时我们就需要用另一个思想:「「自己在前后端都分别开辟一个空间来存储用户信息」」。
token 就是这样的一种思想。其流程为:
- 客户端使用用户名跟密码请求登录。
- 服务端收到请求,去验证用户名与密码。
- 验证成功后,服务端再生成一个独一无二的字符串(Token 令牌),并且将这个令牌保存到服务器的缓存中,再把这个 令牌发送给客户端。
- 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里。
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token。
- 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据。
token 带来的好处
- 无状态,可扩展:在客户端存储的
tokens
是无状态的,并且能够被扩展。基于这种无状态和不存储session
信息,负载均衡器能够将用户信息从一个服务器传到其他服务器上。 - 安全:请求中发送
token
而不再发送cookie
,能够防止CSRF
(跨站请求伪造)。即使在客户端使用cookie
存储token
,cookie
也仅仅是一个存储机制而不是用于认证。并且token
是有时效的,一段时间后用户需要重新验证。 - 可扩展性:能够与其他程序共享数据。
- 多平台跨域:每次都是携带绑定自己信息的令牌访问服务器,当在服务集群环境时,不是只能访问某一台指定的服务器,而是通过从缓存服务器中拿出数据,并更具负载均衡器来选择处理的服务器。
Token 的实现
准备阶段
- 使用
Mysql
数据库 - 开启
Redis
缓存 - 使用
springboot
框架
代码段
1. 登录
<form id="login_form" class="login_form"> 用户名:<input type="text" name="username"> <br> 密码:<input type="password" name="password"> <br> <input type="button" value="提交" onclick="login()">form><script type="application/javascript">function login(){ $.ajax({type:"post", // post 请求dataType:"json", // 返回 json 格式url:"http://localhost:8080/login", // 请求路径data:$("#login_form").serialize(), // 表单序列化success: function(result){console.log(result) // 打印结果if(result.code == 200){// 存储 token localStorage.token = result.data; // 将 token 存到 localStorage 里 location.href = "/index"; // 跳转到首页 } },fail:function(err){console.log(err) } }); }script>
@ResourceRedisTemplate redisTemplate; // redis 缓存模板@RequestMapping(value = "/login", method = RequestMethod.POST)@ResponseBodypublic Result login(String username, String password){ System.out.println(username); System.out.println(password); User user = userService.getUser(username, password);if(user != null){// 登录成功,生成 token 令牌 String token = UUID.randomUUID() + ""; // 使用 uuid 生成唯一 key,以此作为 token 令牌 redisTemplate.opsForValue().set(token, user, Duration.ofMinutes(30L)); // 将 token 放到 redis 缓存中,存半个小时return new Result(200, "请求成功", token); }return new Result(400, "请求失败", null);}
2. 资源访问请求
function requestToken(){ $.ajax({ type:"get", // 请求方式 dataType: "json", // 返回格式 url:"http://localhost:8080/getUser", // 请求地址 headers : { "token" : localStorage.token // 设置 header 头,将 token 放到请求头中更加安全 }, success:function(result){ console.log(result) } })}
@RequestMapping("/getUser")@ResponseBodypublic Result getUserOfLogin(HttpServletRequest request){ String token = request.getHeader("token"); // 从请求头中获取 token Object user = redisTemplate.opsForValue().get(token); // 在 redis 缓存中寻找 token 对应的信息
if(user != null){ // 获取成功,封装返回值 return new Result(200, "请求成功", user); } return new Result(400, "找不到用户信息", null); // 可能没存在这个 token 或者 token 以过期}
3. 注销
function logout(){ $.ajax({ type:"get", url:"http://localhost:8080/logout", dataType:"json", headers:{ "token":localStorage.token }, success:function(result){ localStorage.removeItem("token"); // 在浏览器端清除 token },fail : function(err){ console.log(err) } })}
@RequestMapping("/logout")@ResponseBodypublic Result logout(HttpServletRequest request){ String token = request.getHeader("token"); // 从请求头中获取 token Boolean delete = redisTemplate.delete(token); // 根据 token 删除 redis 缓存里对应的信息 if(delete){ return new Result(200, "注销成功", null); }else{ return new Result(400, "注销失败", null);
}}
前端怎么存token_学长:说说你理解的 Token相关推荐
- 前端中DOM是什么,怎样理解dom
前端中DOM是什么,怎样理解? 首先我们来说一下DOM是什么? 文档对象模型(Document Object Model,简称DOM).我个人认为他就是将,通过浏览器的一些规则解析后,在渲染成我们能够 ...
- 移动前端开发之viewport,devicePixelRatio的深入理解
移动前端开发之viewport的深入理解 在移动设备上进行网页的重构或开发,首先得搞明白的就是移动设备上的viewport了,只有明白了viewport的概念以及弄清楚了跟viewport有关的met ...
- 前端必经之路:CSS页面布局(深入理解浮动布局、定位布局、圣杯布局和双飞翼布局等重要布局方案)
建筑师在对一栋建筑物进行施工之前,首先会根据建筑图纸上的平面图.立体图.剖面图和构造详图等对建筑物进行整体布局后再从局部施工(当然不排除有先装修完厕所再砌卧室围墙的奇葩).在一个网页页面的搭建过程中, ...
- 作为前端,我对业务的一点理解
一直都是写关于技术的一些东西,从来没想过我会写一篇与技术没什么关系的文章,因为在之前的我看来,这种文章完全就是假大空 技术至上? 三年前我毕业进入第一家公司,个人很水的技术能力让我经常在实际的开发工作 ...
- web前端面试高频考点——Vue原理(理解MVVM模型、深度/监听data变化、监听数组变化、深入了解虚拟DOM)
系列文章目录 内容 参考链接 Vue基本使用 Vue的基本使用(一文掌握Vue最基础的知识点) Vue通信和高级特性 Vue组件间的通信及高级特性(多种组件间的通信.自定义v-model.nextTi ...
- Web前端学习笔记:Vue生命周期理解
一.感谢原创博主 示例代码出处====vue2.0 探索之路--生命周期和钩子函数的一些理解 官方文档 二.生命周期简单描述 总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后. 创建前/ ...
- 对前端界面工程师这个职位是怎么样理解的?
a. 前端是最贴近用户的程序员,前端的能力就是能让产品从 90分进化到 100 分,甚至更好 b. 参与项目,快速高质量完成实现效果图,精确到1px: c. 与团队成员,UI设计,产品经理的沟通: d ...
- 面试题系列(9):对前端界面工程师这个职位是怎么样理解的?
a. 前端是最贴近用户的程序员,前端的能力就是能让产品从 90分进化到 100 分,甚至更好 b. 参与项目,快速高质量完成实现效果图,精确到1px: c. 与团队成员,UI设计,产品经理的沟通: d ...
- 爱创课堂每日一题第五十六天-对前端界面工程师这个职位是怎么样理解的?它的前景会怎么样?...
前端是最贴近用户的程序员,比后端.数据库.产品经理.运营.安全都近. 1.实现界面交互 2.提升用户体验 3.有了Node.js,前端可以实现服务端的一些事情 前端是最贴近用户的程序员,前端的能力就是 ...
最新文章
- CQRS及.NET中的参考资料
- (0084)iOS开发之测试iOS远程消息推送
- 我要放弃RedHat Linux了
- opencv实现快速傅立叶变换和逆变换
- HADOOP都升级到2.5啦~~~
- Hive开发要知道数据仓库的四个层次设计
- docker代理设置ssl证书_docker - 设置HTTP/HTTPS 代理
- 分享按钮 html代码,超简洁微博分享按钮代码
- ue4相机_UE4.24源码分析 - PlayerStart
- 机器狗vs警犬!在波士顿动力面前,真狗只能“战术撤退”
- RAR 5.50 控制台使用记录
- Node:连接MySQL报错\lib\protocol\Parser.js:43 Cannot read property ‘query‘ of undefined
- GlobalMapper20坐标转换
- 嵌入式软件工程师学习路线图
- SAP采购订单价格与信息记录价格不匹配
- 微信群活码生成系统,群活码、客服活码、一套非常棒的免费开源群活码系统
- 现代软件工程第三章练习与讨论(补)
- ALV字段目录lvc_s_fcat
- 慕尼黑大学计算机语言学,慕尼黑大学,斯图加特大学和萨尔大学的计算语言学硕士如何选择?...
- TCP协议的通讯流程
热门文章
- pytorch学习——构建多元线性回归的网络结构
- Linux文件名中加入时间
- mysql在线增加字段_MySQL在线加字段实现原理
- wpf 图片绝对路径引用_Python Pillow 图片处理
- 灯泡亮度控制单片机_如何有效保护投影机灯泡 保护投影机灯泡方法【详解】...
- java复选框只会选中一个_java复选框选中
- linux getline函数用法,get()与getline()
- 浮点数规格化-不同基数的规格化
- 在Silverlight 和WPF中使用预编译指令 if..else..endif (译)
- python循环引用是什么_细说Python的循环调用、循环引用和循环导入