授权认证基础

认证 (Authentication) 和授权 (Authorization)的区别是什么?

说简单点就是:

  • 认证 (Authentication): 你是谁。

  • 授权 (Authorization): 你有权限干什么。

稍微正式点(啰嗦点)的说法就是 :

  • Authentication(认证) 是验证您的身份的凭据(例如用户名/用户 ID 和密码),通过这个凭据,系统得以知道你就是你,也就是说系统存在你这个用户。所以,Authentication 被称为身份/用户验证。

  • Authorization(授权) 发生在 Authentication(认证) 之后。授权嘛,光看意思大家应该就明白,它主要掌管我们访问系统的权限。比如有些特定资源只能具有特定权限的人才能访问比如 admin,有些对系统资源操作比如删除、添加、更新只能特定人才具有。

RBAC 模型

系统权限控制最常采用的访问控制模型就是 RBAC 模型

什么是 RBAC 呢?

RBAC 即基于角色的权限访问控制(Role-Based Access Control)。这是一种通过角色关联权限,角色同时又关联用户的授权的方式。

简单地说:一个用户可以拥有若干角色,每一个角色又可以被分配若干权限,这样就构造成“用户-角色-权限” 的授权模型。在这种模型中,用户与角色、角色与权限之间构成了多对多的关系,如下图

RBAC

在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。

本系统的权限设计相关的表如下(一共 5 张表,2 张用户建立表之间的联系):

通过这个权限模型,我们可以创建不同的角色并为不同的角色分配不同的权限范围(菜单)。

Cookie

CookieSession 都是用来跟踪浏览器用户身份的会话方式,但是两者的应用场景不太一样。

维基百科是这样定义 Cookie 的:

Cookies 是某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密)。

简单来说: Cookie 存放在客户端,一般用来保存用户信息

下面是 Cookie 的一些应用案例:

  1. 我们在 Cookie 中保存已经登录过的用户信息,下次访问网站的时候页面可以自动帮你登录的一些基本信息给填了。除此之外,Cookie 还能保存用户首选项,主题和其他设置信息。

  2. 使用 Cookie 保存 SessionId 或者 Token ,向后端发送请求的时候带上 Cookie,这样后端就能取到 Session 或者 Token 了。这样就能记录用户当前的状态了,因为 HTTP 协议是无状态的。

  3. Cookie 还可以用来记录和分析用户行为。举个简单的例子你在网上购物的时候,因为 HTTP 协议是没有状态的,如果服务器想要获取你在某个页面的停留状态或者看了哪些商品,一种常用的实现方式就是将这些信息存放在 Cookie

  4. ......

如何在项目中使用 Cookie 呢?

我这里以 Spring Boot 项目为例。

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) 使用 Spring 框架提供的 @CookieValue 注解获取特定的 cookie 的值

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

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";
}

Cookie 和 Session 有什么区别?

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

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

如何使用 Session-Cookie 方案进行身份验证?

很多时候我们都是通过 SessionID 来实现特定的用户,SessionID 一般会选择存放在 Redis 中。举个例子:

  1. 用户成功登陆系统,然后返回给客户端具有 SessionIDCookie

  2. 当用户向后端发起请求的时候会把 SessionID 带上,这样后端就知道你的身份状态了。

关于这种认证方式更详细的过程如下:

 

 

  1. 用户向服务器发送用户名、密码、验证码用于登陆系统。

  2. 服务器验证通过后,服务器为用户创建一个 Session,并将 Session 信息存储起来。

  3. 服务器向用户返回一个 SessionID,写入用户的 Cookie

  4. 当用户保持登录状态时,Cookie 将与每个后续请求一起被发送出去。

  5. 服务器可以将存储在 Cookie 上的 SessionID 与存储在内存中或者数据库中的 Session 信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。

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

  • 依赖 Session 的关键业务一定要确保客户端开启了 Cookie

  • 注意 Session 的过期时间。

多服务器节点下 Session-Cookie 方案

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

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

如何避免上面这种情况的出现呢?

 

  1. 某个用户的所有请求都通过特性的哈希策略分配给同一个服务器处理。这样的话,每个服务器都保存了一部分用户的 Session 信息。服务器宕机,其保存的所有 Session 信息就完全丢失了。

  2. 每一个服务器保存的 Session 信息都是互相同步的,也就是说每一个服务器都保存了全量的 Session 信息。每当一个服务器的 Session 信息发生变化,我们就将其同步到其他服务器。这种方案成本太大,并且,节点越多时,同步成本也越高。

  3. 单独使用一个所有服务器都能访问到的数据节点(比如缓存)来存放 Session 信息。为了保证高可用,数据节点尽量要避免是单点。

什么是 Token?什么是 JWT?

我们在前面的问题中探讨了使用 Session 来鉴别用户的身份,并且给出了几个 Spring Session 的案例分享。 我们知道 Session 信息需要保存一份在服务器端。这种方式会带来一些麻烦,比如需要我们保证保存 Session 信息服务器的可用性、不适合移动端(依赖 Cookie)等等。

有没有一种不需要自己存放 Session 信息就能实现身份验证的方式呢?

有的!我们基于 Token(令牌) 来做身份验证即可!我们这里说的是 Acesss Token,指的是访问资源接口(API)时所需要的凭证,比如说你访问 Github 的一些 API 的时候,需要带上一个 Token 来表明你有权访问。

JWT (JSON Web Token) 是目前最流行的跨域认证解决方案,是一种基于 Token 的认证授权机制。 从 JWT 的全称也可以看出,JWT 本身也是 Token,一种规范化之后的 JSON 结构的 Token。

JWT 由 Header、Payload、Signature(签名) 这三部分组成,本质上就是一段签名的 JSON 格式的数据。由于它是带有签名的,因此接收者可以验证它的真实性。

通过 JWT ,服务器端就不需要保存 Session 了,只用在客户端保存服务端返回的 Token 就可以了,扩展性得到提升。

 

posted @ 2022-09-13 15:22  埋头搬砖  阅读(226)  评论(0编辑  收藏  举报