文章目录
前言
http是无状态协议,与自己主机不同,http本身并不能判断你在访问了本页面之前还访问了哪个页面,说通俗一点,就是页面本身并不能记录你之前的浏览记录或者操作记录。
最直接的需求就是登录需求,当我们需要完成登录的操作时,就要记录我们的登录信息,从而达到一次登录,一直访问的效果,不然用户每次跳转页面都要重新登录,体验感极差。
要做到这一点,我们就要用到会话跟踪技术。
而cookie 、session、令牌,这些都是会话跟踪技术。
一、cookie
1.1、cookie是什么?
当客户端给服务器端发送请求后,服务器端在响应数据的时候:
=> 服务器端会自动生成一个cookie,并将其响应给浏览器。
=>客户端在接收到响应回来的数据之后,会自动将cookie存储在浏览器本地。
=> 在后续的请求中,客户端每次访问服务器,都会携带cookie到服务器端。
假如这个cookie命令写在登录页面上,当客户端访问了登录页面,并且访问成功,服务器就会提供一个cookie响应给客户端浏览器,后续客户端在访问的时候,只要携带了这个cookie就说明曾经登录过。
1.2、设置cookie:
设置cookie需要用到HttpServletResponse接口,但是不建议直接实现接口或者创建实现类对象,建议以参数的形式存在~
代码如下(示例):
@GetMapping("/c1")
public void cookieAddTest(HttpServletResponse httpServletResponse){
//设置cookie
httpServletResponse.addCookie(new Cookie("id","10086"));
httpServletResponse.addCookie(new Cookie("name","zhangsan"));
httpServletResponse.addCookie(new Cookie("password","123456"));
}
addCookie( ) 需要一个cookie对象,直接new一个就好了,cookie对象又需要两个参数,分别是name和value,是不是很像map,没错就是键值对的形式,一个键对应一个值。直接启动! 我们看一下浏览器的响应,记得打开F12噢 ( 部分笔记本用户是fn+F12 )
在浏览器的响应头里面,就可以看到我们刚才设置的cookie了。
1.3、获取cookie
呐我们设置了cookie,后端程序能不能拿到呢?怎么拿呢?
直接上代码(示例):
@GetMapping("/c2")
public void cookieGetTest(HttpServletRequest httpServletRequest){
Cookie[] cookies = httpServletRequest.getCookies();
for (Cookie cookie : cookies) {
System.out.println(cookie.getName()+":"+cookie.getValue());
}
}
使用HttpServletRequest 的getCookies( ) 就可以获取所有的cookie对象了,访问c2后,结果直接打印在控制台的效果就是这样的
1.4、cookie 的优缺点
优点:
Http协议中支持的技术,浏览器自动进行。
缺点:
①移动端(安卓、iOS)不支持cookie
②不安全,用户可以手动禁用cookie,并且可以修改 (科学手段)
③cookie无法跨域。
二、session
2.1、session是什么?
session的底层还是cookie,但与之不同的是:cookie是保存到浏览器本地,本身并不安全,而session是保存在服务器端的,每次访问服务器端,服务器端就会生成一个session对象,保存到服务器端。然后响应给客户端一个JSESSIONID。下一次客户端来访问时,就会携带这个JSESSIONID,服务端就根据这个id去查找对应的session对象,如果匹配成功,说明曾经登录过,匹配失败就说明未曾登录。
第一次请求:
后续请求:
2.2、设置session
设置session需要用到HttpSession接口
代码如下(示例):
@GetMapping("/s1")
public void session1(HttpSession session) {
session.setAttribute("loginUser", "tom"); //往session中存储数据
session.setAttribute("loginUser", "Jerry"); //往session中存储数据
session.setAttribute("loginUser1", "tom1"); //往session中存储数据
}
session也是key - value键值对的形式~
话不读说,直接启动!看效果:
这个JSESSIONID就会响应到客户端,客户端下一次访问的时候就会携带这个JSESSIONID,来匹配刚才的session对象。
2.3、获取session
获取session需要用到HttpSession接口,但是一般情况下我们都先用HttpServletRequest去获取HttpSession对象,然后再获取session。因为上一个DispatcherServlet获取完可以直接传递。
代码如下(示例):
@GetMapping("/s2")
public void session2(HttpServletRequest request) {
//获取HttpSession对象
HttpSession session = request.getSession();
//从session中获取数据
Object loginUser = session.getAttribute("loginUser1");
}
注意看浏览器请求头中的信息,cookie里面就携带了刚才生成的JSESSIONID,并且直接输出loginUser就可以在控制台看到session封装的东西啦~
2.4、session的优缺点
优点:
底层是cookie,cookie有的session都有,并且还解决了cookie不安全的特点。
缺点:
①服务端集群状态下无法直接使用session
②移动端无法使用cookie
③用户可以自己禁用cookie
④cookie无法跨域
三、令牌
3.1、令牌是什么
令牌,听名字感觉高大上的,但是其本质就是一个字符串,通过一系列算法加密而成。当客户端首次访问某个特定的服务器端时,会生成一个令牌,后续每次访问都会带着这个令牌一同前来,服务器端会校验令牌的真实性、合法性。
以JWT令牌为例:
3.2、JWT令牌的组成:
jwt令牌由三部分组成 : A.B.C
其中
A是(Header):令牌的算法以及令牌的类型 比如 :HS256算法,JWT
B是(Payload):记录了令牌中真实的数据,比如:id、username、password等等
C是(Signature):HS256算法加密(Base64加密(A)+ Base64加密 (B) )
签名(Signature)的目的就是为了防止jwt令牌被篡改,一旦令牌中有任何一部分的任何一个字符被修改了,在校验令牌的时候都会失效,直接报错。
3.3、生成JWT令牌
想要生成JWT令牌,就需要先导入jwt的依赖~
依赖如下:(注意版本问题噢~)
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
导入依赖之后,就可以直接生成令牌啦~
String name = Jwts.builder()
.setClaims(map)
.signWith(SignatureAlgorithm.HS256, "name")
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 30))
.compact();
分别解释一下这几个点点点是什么意思~
Jwts.bulider( ) : 可以理解为生成器的意思
.setClaims(map) : 真实的数据,一般是键值对的形式
.signWith(SignatureAlgorithm.HS256, “name”) :设置算法、令牌名字(签名)
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 30)) : 设置令牌存活时间,1000毫秒= 1秒,以此类推
.compact() :结构、契约,可以理解为以上述条件生成令牌
3.4、解析令牌
能创建,自然能解析!
Claims claims = Jwts.parser()
.setSigningKey("令牌的名字(签名)")
.parseClaimsJws("jwt令牌")
.getBody();
分别解释一下这几个点点点是什么意思:
Jwts.parser() : 调用JWT的解析器
.setSigningKey(“令牌的名字”) : 设置签名,可以理解为获得jwt令牌的名字
.parseClaimsJws(“jwt令牌”) : 解析传入进来的令牌代码
.getBody(); : 获取jwt令牌体
3.5、JWT令牌的优缺点
优点:
①支持PC端、移动端
②解决了集群环境下的认证问题
③减轻了服务器的存储压力
缺点:
相比于cookie和session,JWT令牌需要手动实现(生成、传递、校验)等等
其实,使用JWT令牌更多时候都是以工具类的形式出现
总结
充电时刻
总的来说,cookie、session、令牌这三种会话跟踪技术,都是在访问了一个特殊页面后,给客户端浏览器打一个标签,在标签有效期内,都不用重复做这件事。
cookie的标签存储在客户端的电脑上,并且访问的时候在浏览器的控制台,所有信息一览无遗,非常的不安全。
而session的存在,就是来弥补cookie的不足的。因为session的底层就是cookie,只不过与之不同的是,cookie的标签存在客户端浏览器上,session的标签存在服务器端上。
但是cookie与session本身都有局限性,无法处理集群、跨域、移动端的标记,非常的不方便。因此就有了令牌。
以JWT令牌为例,它既实现了跨域,有实现了移动端的标记,而且信息还是层层加密,非常的安全,非常的可靠。