认证授权基础概念

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

这是⼀个绝⼤多数⼈都会混淆的问题。⾸先先从读⾳上来认识这两个名词,很多⼈都会把它俩的读⾳搞混,所以我建议你先先去查⼀查这两个单词到底该怎么读,他们的具体含义是什么。

说简单点就是:

  • 认证 (Authentication): 你是谁。
  • 授权 (Authorization): 你有权限干什么。

稍微正式点的说法就是:

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

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

认证:


认证登录

授权:


授权

这两个⼀般在我们的系统中被结合在⼀起使⽤,⽬的就是为了保护我们系统的安全性。

2.RBAC 模型了解吗?

RBAC(Role-Based Access Control)是一种基于角色的访问控制模型,用于管理系统中的用户权限。在RBAC模型中,用户被分配到不同的角色,而每个角色具有一组特定的权限。通过将用户分配给角色,而不是直接给用户分配权限,RBAC模型简化了权限管理和维护,并增强了系统的安全性和可管理性。

简单来说:就是一个“用户-角色-权限”的授权模型。在这种模型中,用户与角色,角色与权限之间构成了多对多的关系,如下图:


RBAC权限模型示意图

RBAC模型主要由以下几个核心概念组成:

  1. 用户(User):系统中的实体,可以是个人用户或者其他实体,需要访问系统资源。
  2. 角色(Role):在RBAC模型中,角色是权限的集合。每个角色可以被分配给一个或多个用户。一个用户可以拥有多个角色,从而具备多个权限。
  3. 权限(Permission):权限是系统中某个操作或功能的许可。例如,读取、写入、删除等操作都可以作为权限。
  4. 资源(Resource):资源是系统中需要受到访问控制的对象,例如文件、数据库记录等。

在RBAC模型中,用户通过角色与权限进行关联,从而获得对资源的访问权限。具体来说,一个用户被分配给一个或多个角色,而每个角色则包含了一组权限。当用户需要访问某个资源时,系统会首先检查用户所属的角色是否拥有对该资源的访问权限,如果有,则允许访问,否则拒绝访问。

RBAC模型的优点包括:

  • 简化权限管理:RBAC模型将权限管理从用户级别转移到角色级别,简化了权限的分配和撤销过程。
  • 增强安全性:RBAC模型避免了权限的过度赋予,确保用户只能访问其所需的资源,从而增强了系统的安全性。
  • 易于维护:RBAC模型的权限管理集中在角色层面,便于管理和维护系统的权限配置。
  • 可扩展性:RBAC模型支持灵活的角色配置,可以根据系统需求进行扩展和调整。

在实际应用中,RBAC模型被广泛应用于各种系统和应用程序,特别是对于涉及大量用户和复杂权限控制的系统,RBAC模型可以提供有效的权限管理解决方案。

3.什么是Cookie?Cookie的作用是什么?


Cookie是一种存储在用户计算机中的小型文本文件,用于在Web浏览器和Web服务器之间传递数据。当用户访问一个网站时,服务器可以通过HTTP响应将一个或多个Cookie发送到用户的浏览器中。浏览器会将这些Cookie保存在用户的计算机上,并在之后的每次请求中将这些Cookie发送回服务器。

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

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

4.如何在项目中使用Cookie呢?

以SpringBoot项目为例,通过javax.servlet.http.Cookie类来创建和设置Cookie。Spring Boot提供的HttpServletResponse对象可以用于添加Cookie到响应中,而HttpServletRequest对象可以用于读取请求中的Cookie。

**1)设置Cookie返回给客户端

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class MyController {

    @GetMapping("/setCookie")
    public String setCookie(HttpServletResponse response) {
        // 创建Cookie对象
        Cookie cookie = new Cookie("username", "john_doe");
        // 设置Cookie的有效期,单位为秒
        cookie.setMaxAge(3600); // 1小时
        // 设置Cookie的路径,根路径下的所有URL都可以访问到该Cookie
        cookie.setPath("/");
        // 将Cookie添加到响应中
        response.addCookie(cookie);

        return "Cookie已设置";
    }
}

2) 获取Cookie:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class MyController {

    @GetMapping("/getCookie")
    public String getCookie(HttpServletRequest request) {
        // 从请求中获取所有Cookie
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            // 遍历Cookie数组,找到名为"username"的Cookie
            for (Cookie cookie : cookies) {
                if ("username".equals(cookie.getName())) {
                    // 获取Cookie的值
                    String username = cookie.getValue();
                    return "当前用户:" + username;
                }
            }
        }

        return "未找到Cookie";
    }
}

上述代码中,setCookie方法用于设置Cookie,通过HttpServletResponseaddCookie方法将Cookie添加到响应中。getCookie方法用于获取Cookie,通过HttpServletRequestgetCookies方法获取请求中的所有Cookie,并遍历查找名为"username"的Cookie。

5.Cookie 和 Session 有什么区别?

Session 的主要作用就是通过服务端记录用户的状态。Cookie和Session都是在Web应用程序中用于存储信息的机制,但它们有一些区别:

  1. 存储位置:
    • Cookie:存储在客户端浏览器中,以文本文件的形式存储在用户的计算机上。
    • Session:存储在服务器端,通常在服务器的内存中,也可以持久化到数据库或其他存储介质。
  2. 安全性:
    • Cookie:由于存储在客户端,可能会被篡改或盗用,因此不适合存储敏感信息。
    • Session:存储在服务器端,不容易被用户篡改或盗用,相对安全。
  3. 存储容量:
    • Cookie:每个域名下的Cookie数量和总大小都有限制,通常每个域名下的Cookie数量限制为几十个,总大小限制为几KB到几MB。
    • Session:存储在服务器端,理论上没有大小限制,但实际上受限于服务器内存和存储空间的大小。
  4. 生命周期:
    • Cookie:可以设置Cookie的过期时间,可以是会话Cookie(仅在会话期间有效)或持久Cookie(设置了过期时间,可以在多次会话中有效)。
    • Session:通常在用户第一次访问服务器时创建,并在用户会话结束时销毁,可以通过设置过期时间或手动销毁来控制其生命周期。
  5. 使用场景:
    • Cookie:适合存储一些较小的、不敏感的数据,如用户偏好设置、登录状态等。
    • Session:适合存储较大或敏感的数据,如用户登录信息、购物车内容等。

总的来说,Cookie和Session都是用于在Web应用程序中存储信息的方式,但由于存储位置、安全性、存储容量和生命周期等方面的差异,它们适用于不同的场景。在实际开发中,通常会根据需求来选择使用Cookie还是Session,或者两者结合使用。

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

使用Session-Cookie方案进行身份验证是Web应用程序中常见的一种方式。该方案的基本思路是:

  1. 在用户登录成功后,服务器端创建一个Session,并将Session的唯一标识(通常是一个随机生成的字符串)通过Cookie的方式发送给客户端浏览器。
  2. 客户端浏览器在后续的请求中会携带该Cookie,服务器端通过解析Cookie中的Session标识来验证用户身份。

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

Session-Cookie 身份验证方案

以下是使用Session-Cookie方案进行身份验证的一般步骤:
1. 用户登录:用户在登录页面输入用户名和密码,并提交登录请求到服务器端。
2. 身份验证:服务器端接收到登录请求后,验证用户的用户名和密码是否正确。如果验证通过,说明用户登录成功。
3. 创建Session:登录成功后,服务器端创建一个Session,并将Session的唯一标识保存在服务器端的存储介质中(例如内存、数据库等)。
4. 设置Cookie:服务器端将Session的唯一标识通过Cookie的方式发送给客户端浏览器。通常,这个Cookie的名称和值是在服务器端设置的,而过期时间可以根据需要进行设置,可以是会话Cookie(仅在会话期间有效)或持久Cookie(设置了过期时间,可以在多次会话中有效)。
5. 请求携带Cookie:在后续的请求中,客户端浏览器会自动携带该Cookie,每次请求都会将Cookie发送给服务器端。
6. 身份验证:服务器端通过解析请求中的Cookie,获取Session的唯一标识,并与服务器端保存的Session进行匹配。如果匹配成功,说明用户身份验证通过;否则,说明用户身份验证失败。
7. 登出:用户在退出登录时,服务器端可以销毁对应的Session,同时设置Cookie过期,使得该Cookie失效,从而实现登出操作。

需要注意的是,为了增加安全性,建议在传输过程中对Cookie进行加密和签名,以防止信息被篡改。此外,还可以设置Cookie的HttpOnly属性,防止Cookie被JavaScript访问,从而增加Cookie的安全性。

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

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

7.多服务器节点下 Session-Cookie 方案如何做?

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

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

我们应该如何避免上面这种情况的出现呢?

有几个方案可供大家参考:

  1. 使用共享存储:在多服务器节点之间共享 Session 数据。可以使用分布式缓存系统(如 Redis)来存储 Session 数据,所有服务器节点都连接到同一个 Redis 服务器,从而实现共享 Session。

  2. 使用粘性会话(Sticky Session):在负载均衡器上配置粘性会话,使得同一个用户的请求总是被发送到同一个服务器节点。这样就可以保证用户在同一个服务器上保持相同的 Session,从而实现 Session 在多服务器节点之间的共享。

  3. 使用无状态身份验证:避免使用 Session-Cookie 方案,而是采用无状态的身份验证方式,如 JWT(JSON Web Token)。在无状态身份验证中,所有的用户身份信息都被编码成一个 token,并在每次请求中发送给服务器。服务器不需要保存任何用户状态信息,从而避免了 Session 在多服务器节点之间的共享问题。

7. 如果没有 Cookie 的话 Session 还能用吗?

如果没有 Cookie,Session 仍然可以用,但是需要采用其他方式来传递Session IDSession ID是用来标识用户会话的唯一标识符,通常保存在 Cookie 中。如果没有 Cookie,可以使用其他方式将 Session ID传递给服务器,例如在 URL 参数中传递,或者在请求头中添加自定义字段。

但是需要注意,不使用 Cookie 来保存 Session ID 会引入一些安全风险。例如,在 URL 参数中传递Session ID可能会导致泄露 Session ID,从而增加会话劫持和会话固定攻击的风险。因此,如果不使用 Cookie,需要采取其他措施来保护 Session ID的安全性。

8.为什么 Cookie 无法防止 CSRF 攻击,而 Token 可以?

Cookie 无法防止 CSRF(Cross-Site Request Forgery,跨站请求伪造)攻击主要是因为浏览器会自动将 Cookie 添加到请求中,而攻击者可以利用这一点伪造请求,实现跨站点伪造请求。

在 CSRF 攻击中,攻击者会构造一个特制的网页或链接,诱使用户点击或访问。一旦用户在已登录的状态下点击了这个特制的链接,浏览器会自动将用户的 Cookie 添加到请求中,然后发送给目标网站。由于目标网站对于请求的来源没有进行验证,所以会误认为这是一个合法的请求,进而执行攻击者指定的操作,比如修改用户信息、转账等。

而使用 Token 可以防止 CSRF 攻击的主要原因在于 Token 的验证机制。在使用 Token 时,服务器会在用户登录后生成一个随机的 Token,并将 Token 返回给客户端。客户端在后续的请求中需要携带这个 Token,而服务器会验证 Token 的合法性,只有在 Token 是合法的情况下才会处理请求。

这样一来,即使攻击者构造了一个特制的请求,但由于请求中没有携带正确的 Token,服务器会拒绝处理该请求,从而防止 CSRF 攻击。

总结起来,Cookie 无法防止 CSRF 攻击是因为浏览器会自动携带 Cookie,而攻击者可以利用这一点进行伪造请求。而 Token 可以防止 CSRF 攻击是因为服务器会验证 Token 的合法性,只有合法的 Token 才会被处理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容