会话技术------Cookie、Session、Token(JWT)详解

引言

会话技术概述

用户打开浏览器,访问站点服务器,连续操作(连续的访问站点服务器web资源),直到关闭浏览器,这个整个过程就叫做会话。会话技术是一种在网络通信中用于跟踪用户状态的机制,它可以让服务器在处理用户请求时保持特定用户的状态信息,从而实现个性化的服务和用户体验。

会话技术的由来与发展历程

HTTP 协议是一种无状态协议,每个请求都是相互独立的,服务器无法直接识别来自同一个用户的连续请求。这导致了一些问题,例如无法跟踪和管理用户状态信息、无法提供个性化服务等。所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。于是会话技术就应运而生了。

为了解决这些问题,人们开始探索如何实现会话管理。最初的方案是基于 Cookie 的会话管理。Cookie 是一种在客户端存储数据的机制,服务器可以在响应中设置 Cookie,然后在后续的请求中读取 Cookie。通过将会话标识符(Session ID)存储在 Cookie 中,服务器能够识别特定用户的请求并保持其状态信息。Cookie 在浏览器中存储,可以设置过期时间,也可以通过设置路径和域名来限制 Cookie 的范围。

为了更好地管理会话,开发人员开始使用服务器端的会话存储来替代完全依赖于 Cookie。这就是 Session-Based Session 技术(Session技术)。服务器会为每个会话分配一个唯一的 Session ID,并将该 ID 存储在服务器端的会话存储中,而不是直接依赖于客户端的 Cookie。客户端的 Cookie 只包含 Session ID,服务器通过 Session ID 来查找对应的会话数据。这样可以增加对会话的控制和安全性,但需要在服务器端维护会话存储。

随着移动设备和分布式系统的兴起,无状态会话管理变得更加重要。Token-Based Session 技术(Token技术)应运而生。在这种技术中,服务器使用 Token(令牌)来表示会话状态。当用户登录成功后,服务器生成一个加密的 Token,并将其发送给客户端。客户端在后续的请求中将 Token 带上,服务器通过解析和验证 Token 来识别和管理会话。由于 Token 是无状态的,服务器不需要维护会话存储,可以更好地适应分布式环境。

什么是Cookie

Cookie是一种在客户端(通常是Web浏览器)和服务器之间传输的小型文本文件。它由服务器通过HTTP响应的头部设置,并存储在客户端的浏览器中。当客户端发送后续请求时,会将该Cookie信息包含在HTTP请求头中发送给服务器。

Cookie认证流程

Cookie认证流程通常包括以下步骤:

  1. 用户访问需要身份验证的网站。如果用户未经过身份验证,则服务器将重定向用户到登录页面。
  2. 用户输入用户名和密码,发送Http请求传递给服务器进行验证。
  3. 服务器验证用户的凭据,并创建一个会话来保存用户的身份验证状态。在这个过程中,服务器生成一个唯一的标识符Session ID,并将其存储在服务器端。
  4. 服务器将Session ID发送到客户端的浏览器中,通常是将Cookie放在Http请求响应的请求头中,在请求头中有一系列的以Set-Cookie为键的键值对,在这些键值对中包含有Session ID、到期日期、作用域和有效时间等信息。
  5. 当用户发送后续请求时,浏览器会将Session ID作为Cookie的一部分自动包含在HTTP请求头中。
  6. 服务器解析请求头中的Session ID,并将Cookie中的Session ID与数据库中的Session进行比较以验证用户的有效性。
  7. 如果会话ID有效且相关联的身份验证状态信息表明用户已经通过身份验证,则服务器可以允许请求并提供所需的响应。否则,服务器可能会拒绝请求或重定向用户到登录页面以重新验证。

下面是Cookie认证流程图

会话技术------Cookie、Session、Token(JWT)详解_第1张图片

代码测试

package com.kjz;

import com.kjz.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * HttpCookie演示
 */
@Slf4j
@RestController
public class SessionController {

    //设置Cookie
    @GetMapping("/c1")
    public Result cookie1(HttpServletResponse response){
        response.addCookie(new Cookie("login_username","kjz")); //设置Cookie/响应Cookie
        return Result.success();
    }

    //获取Cookie
    @GetMapping("/c2")
    public Result cookie2(HttpServletRequest request){
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            if(cookie.getName().equals("login_username")){
                System.out.println("login_username: "+cookie.getValue()); //输出name为login_username的cookie
            }
        }
        return Result.success();
    }

    }
}

A.访问 c1 接口,设置Cookie ,http://localhost:8080/c1

会话技术------Cookie、Session、Token(JWT)详解_第2张图片

 我们可以看到,设置的cookie,通过响应头Set-Cookie响应给浏览器,并且浏览器会将Cookie,存储在浏览器端。

会话技术------Cookie、Session、Token(JWT)详解_第3张图片

B. 访问c2接口 http://localhost:8080/c2,此时浏览器会自动的将Cookie携带到服务端,是通过请求头Cookie,携带的

会话技术------Cookie、Session、Token(JWT)详解_第4张图片

优缺点

  • 优点:HTTP协议中支持的技术(像Set-Cookie 响应头的解析以及 Cookie 请求头数据的携带,都是浏览器自动进行的,是无需我们手动操作的)

  • 缺点

    • 移动端APP(Android、IOS)中无法使用Cookie

    • 不安全,用户可以自己禁用Cookie

    • Cookie不能跨域

Session

什么是Session

Session是一种在Web应用程序中跨请求保持用户状态的机制。

Session是一段服务器上的存储区域,用于存储用户信息和状态。当用户第一次访问Web应用程序时,服务器会创建一个Session,并给它分配一个唯一的标识符(session ID),然后将该标识符发送给客户端。客户端收到session ID后,通常会将其存储在cookie中,以便后续请求时将其发送回服务器。服务器通过session ID可以找到对应的Session,并从中读取或修改用户信息和状态。session 是基于 cookie 实现的,session 存储在服务器端,sessionId 会被存储到客户端的cookie 中

Session认证流程

  • session 认证流程:
    • 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session
    • 请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器
    • 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名
    • 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。

根据以上流程可知,SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。

以下是流程图:

会话技术------Cookie、Session、Token(JWT)详解_第5张图片

代码测试

package com.kjz;

import com.kjz.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * HttpSession演示
 */
@Slf4j
@RestController
public class SessionController {

    @GetMapping("/s1")
    public Result session1(HttpSession session){
        log.info("HttpSession-s1: {}", session.hashCode());

        session.setAttribute("loginUser", "tom"); //往session中存储数据
        return Result.success();
    }

    @GetMapping("/s2")
    public Result session2(HttpServletRequest request){
        HttpSession session = request.getSession();
        log.info("HttpSession-s2: {}", session.hashCode());

        Object loginUser = session.getAttribute("loginUser"); //从session中获取数据
        log.info("loginUser: {}", loginUser);
        return Result.success(loginUser);
    }
}

A. 访问 s1 接口,http://localhost:8080/s1

会话技术------Cookie、Session、Token(JWT)详解_第6张图片

请求完成之后,在响应头中,就会看到有一个Set-Cookie的响应头,里面响应回来了一个字符串,就是JSESSIONID,这个就是服务端会话对象 Session 的ID。

会话技术------Cookie、Session、Token(JWT)详解_第7张图片

Session ID被存储在浏览器的Cookie中。

B. 访问 s2 接口,http://localhost:8080/s2

会话技术------Cookie、Session、Token(JWT)详解_第8张图片

接下来,在后续的每次请求时,都会将Cookie的值,携带到服务端,那服务端呢,接收到Cookie之后,会自动的根据JSESSIONID的值,找到对应的会话对象Session。

会话技术------Cookie、Session、Token(JWT)详解_第9张图片

两次请求,获取到的Session会话对象的hashcode是一样的,就说明是同一个会话对象。而且,第一次请求时,往Session会话对象中存储的值,第二次请求时,也获取到了。 那这样,我们就可以通过Session会话对象,在同一个会话的多次请求之间来进行数据共享了。

优缺点

  • 优点:Session是存储在服务端的,安全

  • 缺点

    • 服务器集群环境下无法直接使用Session

    • 移动端APP(Android、IOS)中无法使用Cookie

    • 用户可以自己禁用Cookie

    • Cookie不能跨域

Cookie与Session的区别和联系

区别

  • 安全性: Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。
  • 存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。
  • 有效期不同: Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
  • 数据存储:
  1. Cookie:Cookie是以键值对的形式存储在客户端的文本文件中。每个Cookie都有名称、值、过期时间、域名等属性。Cookie的数据容量通常有限制,一般为几KB。
  2. Session:Session将用户状态数据存储在服务器端的内存或数据库中。因此,Session可以存储更大量的数据,并且不受Cookie容量限制。
  • 生命周期:
  1. Cookie:可以设置Cookie的过期时间,在过期时间之前,Cookie会一直保留在客户端,除非被删除或过期。
  2. Session:Session的生命周期由服务器控制,通常在用户关闭浏览器或一段时间不活动后过期。过期后,服务器会清理掉相应的Session数据。

联系

Cookie和Session通常是结合使用的。服务器使用Session来管理用户的状态和敏感信息,而将Session ID存储在Cookie中发送给客户端。客户端在后续的请求中会自动携带Cookie中的Session ID,服务器通过Session ID来识别和恢复对应的Session,从而实现跨请求的状态保持。

Token

什么是Token

作为计算机术语时,是“令牌”的意思。Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。

token其实说的更通俗点可以叫暗号,在一些数据传输之前,要先进行暗号的核对,不同的暗号被授权不同的数据操作。说白了token是一个身份卡,有权限的作用。例如在USB1.1协议中定义了4类数据包:token包、data包、handshake包和special包。主机和USB设备之间连续数据的交换可以分为三个阶段,第一个阶段由主机发送token包,不同的token包内容不一样(暗号不一样)可以告诉设备做不同的工作,第二个阶段发送data包,第三个阶段由设备返回一个handshake包。

Token的分类

在Web应用程序中,有各种类型的Token用于身份验证和授权。以下是一些常见的Token类型:

  • 访问令牌(Access Token):用于访问受保护的资源,通常用于OAuth 2.0授权框架中。当用户通过认证服务器获得授权后,会收到一个访问令牌,该令牌可以被发送到资源服务器以获取受保护资源。

  • 刷新令牌(Refresh Token):用于获取新的访问令牌,通常也用于OAuth 2.0授权框架中。刷新令牌可以用来获取新的访问令牌,以避免用户需要重新进行认证流程。

  • JSON Web Token(JWT):一种开放标准(RFC 7519),用于在各方之间安全地传输信息。JWT通常被用作访问令牌,它包含了被加密的用户信息和其他元数据,可以被用于身份验证和授权。

  • ID令牌(ID Token):也通常用于OAuth 2.0认证框架中,用于向客户端提供已认证用户的身份信息。ID令牌通常被用于OpenID Connect协议中。

  • CSRF令牌(Cross-Site Request Forgery Token):用于防止跨站请求伪造攻击。CSRF令牌通常是一个随机生成的值,它会被包含在表单提交中,服务器会验证该令牌以确定请求是否合法。

  • 身份令牌(Identity Token):用于表示用户的身份信息,通常在身份验证过程中使用。

下面详细介绍一下Access Token和Refresh Token这两者常见的令牌

Access Token

Access Token(访问令牌)是OAuth 2.0授权框架中的一种令牌类型,用于标识和验证客户端的访问权限。在OAuth 2.0认证流程中,用户通过认证服务器进行身份验证后,会获得一个Access Token,然后将该Token用于访问受保护的资源服务器。

Token认证流程:

  • 客户端使用用户名跟密码请求登录
  • 服务端收到请求,去验证用户名与密码
  • 验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端
  • 客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里
  • 客户端每次向服务端请求资源的时候需要带着服务端签发的 token
  • 服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据

会话技术------Cookie、Session、Token(JWT)详解_第10张图片

  • 每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里
  • 基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库
  • token 完全由应用管理,所以它可以避开同源策略

Refresh Token

Refresh Token(刷新令牌)是OAuth 2.0授权框架中的一种令牌类型,用于获取新的Access Token(访问令牌),以避免用户需要重新进行认证流程。在OAuth 2.0授权流程中,Refresh Token通常是在用户通过认证服务器进行身份验证后,一并返回给客户端的。

特点:

  • 生命周期较长:相对于Access Token而言,Refresh Token的生命周期较长,可以用来获取多个Access Token,以延长用户的认证状态。

  • 不包含用户信息:Refresh Token通常不包含任何用户信息,只包含用于获取新Access Token的信息,如客户端ID、密钥、过期时间等。

  • 需要安全存储:由于Refresh Token可以用来获取新的Access Token,因此需要被妥善保管,并且在传输过程中需要采用加密等安全措施。

工作流程:

  1. 用户在客户端进行OAuth 2.0授权流程,通过认证服务器进行身份验证,获取Access Token和Refresh Token。

  2. 客户端在后续的请求中使用Access Token进行API访问,当Access Token过期时,客户端会使用Refresh Token向认证服务器请求新的Access Token。

  3. 认证服务器收到Refresh Token,并验证其有效性和权限,如果验证通过,则生成并返回新的Access Token。

  4. 客户端使用新的Access Token进行后续的API访问,直到新的Access Token过期或者再次使用Refresh Token获取新的Access Token。

使用注意点

Refresh Token可以避免用户频繁进行认证流程,提高用户体验。但是它也需要被妥善保管,以避免被恶意利用。在使用Refresh Token时,需要注意以下几点:

  • 安全存储:Refresh Token应该被安全地存储,通常建议使用加密等技术保护其安全性。

  • 过期时间控制:Refresh Token应该具有一定的过期时间,并且客户端需要及时更新Refresh Token,以避免过期而导致无法获取新的Access Token。

  • 权限控制:Refresh Token应该和Access Token一样,具有权限控制机制,确保只有拥有合法Refresh Token的客户端才能获取新的Access Token。

下面是工作流程图:

会话技术------Cookie、Session、Token(JWT)详解_第11张图片

优缺点

  • 优点:

    • 支持PC端、移动端

    • 解决集群环境下的认证问题

    • 减轻服务器的存储压力(无需在服务器端存储)

    • 服务端无状态化、可扩展性好

  • 缺点:需要自己实现(包括令牌的生成、令牌的传递、令牌的校验)

JWT

前面介绍了基于令牌技术来实现会话追踪。这里所提到的令牌就是用户身份的标识,其本质就是一个字符串。令牌的形式有很多,接下来介绍一下一种实现方案:功能强大的 JWT令牌。

介绍

JWT全称:JSON Web Token (官网:JSON Web Tokens - jwt.io)

  • 定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

    简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。

    自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。

    简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。

JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)

  • 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{"alg":"HS256","type":"JWT"}

  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{"id":"1","username":"Tom"}

  • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

    签名的目的就是为了防jwt令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的。

JWT是如何将原始的JSON格式数据,转变为字符串的呢?

其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码

Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号。

需要注意的是Base64是编码方式,而不是加密方式。

JWT的生成和校验

下面说一下基于java代码如何生成和校验JWT令牌

首先我们先来实现JWT令牌的生成。要想使用JWT令牌,需要先引入JWT的依赖:



    io.jsonwebtoken
    jjwt
    0.9.1

然后通过调用工具包中提供的API来完成JWT令牌的生成和校验

工具类:JWTUtils

public class JWTUtils {

    private static String signKey = "kjzshicaibi";//签名密钥
    private static Long expire = 43200000L; //有效时间

    /**
     * 生成JWT令牌
     * @param claims JWT第二部分负载 payload 中存储的内容
     * @return
     */
    public static String generateJwt(Map claims){
        String jwt = Jwts.builder()
                .addClaims(claims)//自定义信息(有效载荷)
                .signWith(SignatureAlgorithm.HS256, signKey)//签名算法(头部)
                .setExpiration(new Date(System.currentTimeMillis() + expire))//过期时间
                .compact();
        return jwt;
    }

    /**
     * 解析JWT令牌
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)//指定签名密钥
                .parseClaimsJws(jwt)//指定令牌Token
                .getBody();
        return claims;
    }
}

通过测试类进行测试

JWT生成:

    /**
     * 生成JWT
     */
    @Test
    public void testGenJwt(){
        Map claims = new HashMap<>();
        claims.put("id",1);
        claims.put("name","tom");
        String jwt = JwtUtils.generateJwt(claims);
        System.out.println(jwt);
    }

输出结果为

会话技术------Cookie、Session、Token(JWT)详解_第12张图片

输出的结果就是生成的JWT令牌,,通过英文的点分割对三个部分进行分割,我们可以将生成的令牌复制一下,然后打开JWT的官网,将生成的令牌直接放在Encoded位置,此时就会自动的将令牌解析出来。

会话技术------Cookie、Session、Token(JWT)详解_第13张图片

第一部分解析出来,看到JSON格式的原始数据,所使用的签名算法为HS256。

第二个部分是我自定义的数据,之前我们自定义的数据就是id,还有一个exp代表的是我所设置的过期时间。

由于前两个部分是base64编码,所以是可以直接解码出来。但最后一个部分并不是base64编码,是经过签名算法计算出来的,所以最后一个部分是不会解析的。

另外在这里插一嘴,我调试的过程中出现了以下的bug

会话技术------Cookie、Session、Token(JWT)详解_第14张图片

产生错误原因:生成JWT的密钥signKey字符串过短引起的异常。

解决方法:尽量将signKey字符串设置长。

之前设置signKey字符串仅仅3个字母字符串 "kjz",现在修改为"kjzshicaibi"

解析JWT:

 @Test
    public void testParseJwt(){
        Claims claims = JwtUtils.parseJWT("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTcwMDgzMzkyN30.tF3EmoKNR5PE-vVZcv0VKgpiaaVgp-mYtkqpBVRbtF4");
        System.out.println(claims);
    }

输出结果

会话技术------Cookie、Session、Token(JWT)详解_第15张图片

JWT认证流程

  1. 用户向服务器发送凭据(例如用户名和密码)以进行身份验证。
  2. 服务器验证用户提供的凭据。如果凭据有效,则服务器生成一个JWT,并将其作为响应返回给客户端。
  3. 客户端收到JWT后,将其存储在本地,通常是在浏览器的Cookie或本地存储中。
  4. 客户端在后续请求中将JWT作为身份验证凭据包含在HTTP请求头中,键值对如下(Authorization: Bearer
  5. 服务器接收到带有JWT的请求后,会对JWT进行验证,确保它是由服务器签发的有效令牌。
  6. 如果JWT验证成功且未过期,服务器将处理请求并提供所需的响应。服务器可以从JWT中获取附加的声明信息,如用户ID、角色等,以进行授权和个性化操作。
  7. 如果JWT验证失败或已过期,服务器会拒绝请求或要求客户端重新进行身份验证。

流程图如下

会话技术------Cookie、Session、Token(JWT)详解_第16张图片

下面是JWT运用到登录场景的一个例子

1.引入JWT工具类

这里的工具类与上面提到的一致就不重复引用了。

2.登录完成后,调用工具类生成JWT令牌并返回

@RestController
@Slf4j
public class LoginController {
    //依赖业务层对象
    @Autowired
    private EmpService empService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {
        //调用业务层:登录功能
        Emp loginEmp = empService.login(emp);

        //判断:登录用户是否存在
        if(loginEmp !=null ){
            //自定义信息
            Map claims = new HashMap<>();
            claims.put("id", loginEmp.getId());
            claims.put("username",loginEmp.getUsername());
            claims.put("name",loginEmp.getName());

            //使用JWT工具类,生成身份令牌
            String token = JwtUtils.generateJwt(claims);
            return Result.success(token);
        }
        return Result.error("用户名或密码错误");
    }
}

利用开发者工具,抓取一下网络请求

会话技术------Cookie、Session、Token(JWT)详解_第17张图片

登录请求完成后,可以看到JWT令牌已经响应给了前端,此时前端就会将JWT令牌存储在浏览器本地。

服务器响应的JWT令牌存储在本地浏览器哪里了呢?

  • 在当前案例中,JWT令牌存储在浏览器的本地存储空间Local Storage中了。 Local Storage是浏览器的本地存储,在移动端也是支持的。

会话技术------Cookie、Session、Token(JWT)详解_第18张图片

之后再发起一个查询数据的请求,此时可以看到在请求头中包含一个token(JWT令牌),后续的每一次请求当中,都会将这个令牌携带到服务端。

会话技术------Cookie、Session、Token(JWT)详解_第19张图片

注意此处我是在前端发请求时自定义了一个名为token的键值对,将JWT放在这个键值对中。一般情况下,默认都是把token放在Authorization的键值对中。

写到此处我的心中又产生了一个问题,为什么要把JWT放在请求头中而不是请求行、请求体中呢

放在请求头中的原因:

安全性

      将JWT放在请求头中可以避免敏感信息被记录在URL中或者浏览器历史记录中。这是因为,请求头中的内容不会自动包含在浏览器历史记录中,也不会自动写入Web服务器的访问日志文件中,从而增加了身份验证信息的安全性。

标准化

      将JWT放在请求头中符合HTTP协议规范。HTTP协议定义了请求行(包括方法、URI和协议版本)和请求头两个部分,其中请求头用于传递一些附加的信息,比如身份验证信息、请求正文类型等。因此,将JWT放在请求头中符合HTTP协议的设计理念,而将它放在请求行或请求体中可能会导致与HTTP协议不兼容的问题。

      将JWT放在请求头中也方便了API开发和使用的标准化。HTTP请求头具有标准的格式和语法,这使得API的开发和使用更加规范和易于实现。相比之下,将JWT放在请求行或者请求体中,可能会需要开发人员自己定义格式和语法,这会增加开发和使用的成本和风险

不放在请求行中的原因

安全性问题:

    请求行通常会被记录在服务器的访问日志中,也可能会被缓存或代理服务器记录下来。如果将JWT放在请求行中,就会将敏感的身份验证信息暴露在这些记录中,增加了被恶意利用的风险。

长度限制:

    请求行的长度是有限制的,根据HTTP协议规范,请求行的总长度(包括方法、URI和协议版本等)应该不能超过几千个字节(不同的浏览器配置不同)。如果将JWT放在请求行中,可能会导致JWT太长而无法满足长度限制,导致请求失败或被截断。

处理复杂:

    请求行的解析和处理通常由HTTP服务器或客户端库自动完成。将JWT放在请求行中可能会导致服务器或库无法正确解析请求行,需要进行额外的处理和解析逻辑,增加了开发和维护的复杂性

不放在请求体中的原因

安全性问题:

     请求体通常会被缓存、记录在服务器的日志中、传输到代理服务器中等。将JWT放在请求体中可能会将敏感信息暴露在这些记录和传输中,增加安全风险。

兼容性问题:

    有些浏览器或客户端可能无法正确处理带有请求体的HTTP请求,或者在处理请求体时出现问题。这可能导致请求失败或出现其他错误。

你可能感兴趣的:(java后端,服务器)