系统设计面试总结:2、认证Authentication(上):Cookie+Springboot使用cookie案例、Session、单体/多节点环境使用 Session-Cookie方案

仅供自学回顾使用,请支持javaGuide原版。

  • 认证 (Authentication): 你是谁。一般指的就是用户认证。
  • 授权 (Authorization): 你有权限干什么。一般指的就是权限管理。

1.Cookie

C

Cookie 存放在客户端,一般用来保存用户信息。
下面是 Cookie 的一些应用案例:

  • Cookie 保存登录过的用户信息,下次访问网站的时候页面可以自动帮你登录的一些基本信息给填了。
  • Cookie 还能保存用户首选项,主题和其他设置信息。
  • Cookie 保存 SessionId 或者 Token ,向后端发送请求的时候带上 Cookie,这样后端就能取到 Session 或者 Token 了。这样就能记录用户当前的状态了,因为 HTTP 协议是无状态的。
  • Cookie 还可以用来记录和分析用户行为。举个简单的例子你在网上购物的时候,因为 HTTP 协议是没有状态的,如果服务器想要获取你在某个页面的停留状态或者看了哪些商品,一种常用的实现方式就是将这些信息存放在 Cookie

2.Springboot如何使用cookie

2.1.设置 Cookie 返回给客户端

@GetMapping("/change-username")
public String setCookie(HttpServletResponse response) {
    
    
    // 创建一个 cookie
    Cookie cookie = new Cookie("username", "Jovan");
    //设置 cookie过期时间
    cookie.setMaxAge(7 * 24 * 60 * 60); // expires in 7 days
    //添加到 response 中
    response.addCookie(cookie);

    return "Username is changed!";
}

2.2.使用 @CookieValue 注解获取特定 cookie 值

@GetMapping("/")
public String readCookie(@CookieValue(value = "username", defaultValue = "Atta") String username) {
    
    
    return "Hey! My username is " + username;
}

2.3.读取所有的 Cookie 值

@GetMapping("/all-cookies")
public String readAllCookies(HttpServletRequest request) {
    
    

    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
    
    
        return Arrays.stream(cookies)
                .map(c -> c.getName() + "=" + c.getValue()).collect(Collectors.joining(", "));
    }
    return "No cookies";
}

3.Session

Session 的主要作用就是通过服务端记录用户的状态。

典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了。

Cookie 数据保存在客户端(浏览器端),Session 数据保存在服务器端。相对来说 Session 安全性更高。如果使用 Cookie 的一些敏感信息不要写入 Cookie 中,最好能将 Cookie 信息加密然后使用到的时候再去服务器端解密。

4.单体环境如何使用 Session-Cookie 方案进行身份验证

SessionID 一般会选择存放在 Redis 中。
在这里插入图片描述

  • 用户向服务器发送用户名、密码、验证码用于登陆系统。
  • 服务器验证通过后,服务器为用户创建一个 Session,并将 Session 信息存储起来
  • 服务器向用户返回一个 SessionID,写入用户的 Cookie。
  • 当用户保持登录状态时,Cookie 将与每个后续请求一起被发送出去。
  • 服务器可以将存储在 Cookie 上的 SessionID 与存储在内存中或者数据库中的 Session 信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。

使用 Session 的时候需要注意下面几个点:

  • 依赖 Session 的关键业务一定要确保客户端开启了 Cookie。
  • 注意 Session 的过期时间。

5.多节点下如何使用 Session-Cookie 方案?

Session-Cookie 方案在单体环境是一个非常好的身份认证方案。但是,当服务器水平拓展成多节点时,Session-Cookie 方案就要面临挑战了。

举个例子:假如我们部署了两份相同的服务 A,B,用户第一次登陆的时候 ,Nginx 通过负载均衡机制将用户请求转发到 A 服务器,此时用户的 Session 信息保存在 A 服务器。结果,用户第二次访问的时候 Nginx 将请求路由到 B 服务器,由于 B 服务器没有保存 用户的 Session 信息,导致用户需要重新进行登陆。

我们应该如何避免上面这种情况的出现呢?有几个方案可供大家参考:

  • 某个用户的所有请求都通过特性的哈希策略分配给同一个服务器处理。这样的话,每个服务器都保存了一部分用户的 Session 信息。但该服务器宕机,其保存的所有 Session 信息就完全丢失了。
  • 每一个服务器保存的 Session 信息都是互相同步的,也就是说每一个服务器都保存了全量的 Session 信息。每当一个服务器的 Session 信息发生变化,我们就将其同步到其他服务器。这种方案成本太大,并且,节点越多时,同步成本也越高。
  • 单独使用一个所有服务器都能访问到的数据节点(比如缓存)来存放 Session 信息。但为了保证高可用,数据节点一般尽量要避免是单点。
  • Spring Session 是一个用于在多个服务器之间管理会话的项目。它可以与多种后端存储(如 Redis、MongoDB 等)集成,从而实现分布式会话管理。通过 Spring Session,可以将会话数据存储在共享的外部存储中,以实现跨服务器的会话同步和共享。最推荐