From b51b8269f57f60b4a1cb86c1abc0b4dec48c8a8f Mon Sep 17 00:00:00 2001 From: VinterHe <37563054+VinterHe@users.noreply.github.com> Date: Fri, 4 Jun 2021 17:17:03 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=87=E7=AB=A0?= =?UTF-8?q?=E4=B8=AD=E8=A3=85=E7=AE=B1=E5=86=99=E6=88=90=E6=8B=86=E7=AE=B1?= =?UTF-8?q?=E7=9A=84=E7=AC=94=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" "b/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" index b11de0c54ad..09fb3269736 100644 --- "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" +++ "b/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" @@ -77,7 +77,7 @@ Integer i2 = new Integer(40); System.out.println(i1==i2);//false ``` -`Integer i1=40` 这一行代码会发生拆箱,也就是说这行代码等价于 `Integer i1=Integer.valueOf(40)` 。因此,`i1` 直接使用的是常量池中的对象。而`Integer i1 = new Integer(40)` 会直接创建新的对象。因此,输出 false 。 +`Integer i1=40` 这一行代码会发生装箱,也就是说这行代码等价于 `Integer i1=Integer.valueOf(40)` 。因此,`i1` 直接使用的是常量池中的对象。而`Integer i1 = new Integer(40)` 会直接创建新的对象。因此,输出 false 。 记住:**所有整型包装类对象之间值的比较,全部使用 `equals()` 方法比较**。 From e450f524158e841c8ce278eca9e82085ff7df275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E8=82=87=E6=98=8E?= Date: Sun, 6 Jun 2021 15:25:16 +0800 Subject: [PATCH 2/9] fix typo --- .../Java\345\206\205\345\255\230\345\214\272\345\237\237.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md" "b/docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md" index 977ee296f4a..5881c817b28 100644 --- "a/docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md" +++ "b/docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md" @@ -103,7 +103,7 @@ Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成 **Java 虚拟机栈会出现两种错误:`StackOverFlowError` 和 `OutOfMemoryError`。** - **`StackOverFlowError`:** 若 Java 虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出 StackOverFlowError 错误。 -- **`OutOfMemoryError`:** Java 虚拟机栈的内存大小可以动态扩展, 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出`OutOfMemoryError`异常异常。 +- **`OutOfMemoryError`:** Java 虚拟机栈的内存大小可以动态扩展, 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出`OutOfMemoryError`异常。 ![](./pictures/java内存区域/《深入理解虚拟机》第三版的第2章-虚拟机栈.png) @@ -498,4 +498,4 @@ i4=i5+i6 true - - - -- 深入解析 String#intern \ No newline at end of file +- 深入解析 String#intern From 2546860ada8cca66b44e250abed1697b40c0dcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E8=82=87=E6=98=8E?= Date: Sun, 6 Jun 2021 17:54:00 +0800 Subject: [PATCH 3/9] fix typo --- ...61\273\345\212\240\350\275\275\350\277\207\347\250\213.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md" "b/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md" index 18cdd0b1452..c79de7df529 100644 --- "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md" +++ "b/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md" @@ -102,7 +102,7 @@ Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚 2. 该类没有在其他任何地方被引用 3. 该类的类加载器的实例已被 GC -所以,在 JVM 生命周期类,由 jvm 自带的类加载器加载的类是不会被卸载的。但是由我们自定义的类加载器加载的类是可能被卸载的。 +所以,在 JVM 生命周期内,由 jvm 自带的类加载器加载的类是不会被卸载的。但是由我们自定义的类加载器加载的类是可能被卸载的。 只要想通一点就好了,jdk 自带的 `BootstrapClassLoader`, `ExtClassLoader`, `AppClassLoader` 负责加载 jdk 提供的类,所以它们(类加载器的实例)肯定不会被回收。而我们自定义的类加载器的实例是可以被回收的,所以使用我们自定义加载器加载的类是可以被卸载掉的。 @@ -120,4 +120,4 @@ Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚 **Java 工程师必备学习资源:** 一些 Java 工程师常用学习资源[公众号](#公众号)后台回复关键字 **“1”** 即可免费无套路获取。 -![我的公众号](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/167598cd2e17b8ec.png) \ No newline at end of file +![我的公众号](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/167598cd2e17b8ec.png) From 1aa12ac44eb1acec138b0bb5e2834965aec9719b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E8=82=87=E6=98=8E?= Date: Sun, 6 Jun 2021 18:46:15 +0800 Subject: [PATCH 4/9] fix typo --- ...7\235\345\270\246\344\275\240\350\256\244\350\257\206JVM.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/docs/java/jvm/[\345\212\240\351\244\220]\345\244\247\347\231\275\350\257\235\345\270\246\344\275\240\350\256\244\350\257\206JVM.md" "b/docs/java/jvm/[\345\212\240\351\244\220]\345\244\247\347\231\275\350\257\235\345\270\246\344\275\240\350\256\244\350\257\206JVM.md" index b80b34c796d..6b7d48ab8a5 100644 --- "a/docs/java/jvm/[\345\212\240\351\244\220]\345\244\247\347\231\275\350\257\235\345\270\246\344\275\240\350\256\244\350\257\206JVM.md" +++ "b/docs/java/jvm/[\345\212\240\351\244\220]\345\244\247\347\231\275\350\257\235\345\270\246\344\275\240\350\256\244\350\257\206JVM.md" @@ -2,7 +2,7 @@ ## 前言 -如果在文中用词或者理解方面出现问题,欢迎指出。此文旨在提及和而不深究,但会尽量效率地把知识点都抛出来 +如果在文中用词或者理解方面出现问题,欢迎指出。此文旨在提及而不深究,但会尽量效率地把知识点都抛出来 ## 一、JVM的基本介绍 From 889493fd933476b90d453a90124591ed344bbdfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E8=82=87=E6=98=8E?= Date: Sun, 6 Jun 2021 23:14:51 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E7=A4=BA=E4=BE=8B=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/java/new-features/java8-common-new-features.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/java/new-features/java8-common-new-features.md b/docs/java/new-features/java8-common-new-features.md index 022a3bc9067..9b5a8384563 100644 --- a/docs/java/new-features/java8-common-new-features.md +++ b/docs/java/new-features/java8-common-new-features.md @@ -798,6 +798,7 @@ public void newFormat(){ //format yyyy-MM-dd HH:mm:ss LocalDateTime dateTime = LocalDateTime.now(); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String dateTimeStr = dateTime.format(dateTimeFormatter); System.out.println(String.format("dateTime format : %s", dateTimeStr)); } ``` @@ -1016,4 +1017,4 @@ System.out.println("本地时区时间: " + localZoned); - Optional - Date time-api -这些都是开发当中比较常用的特征。梳理下来发现它们真香,而我却没有更早的应用。总觉得学习 java 8 新特性比较麻烦,一致使用老的实现方式。其实这些新特性几天就可以掌握,一但掌握,效率会有很大的提高。其实我们涨工资也是涨的学习的钱,不学习终究会被淘汰,35 岁危机会提前来临。 \ No newline at end of file +这些都是开发当中比较常用的特征。梳理下来发现它们真香,而我却没有更早的应用。总觉得学习 java 8 新特性比较麻烦,一致使用老的实现方式。其实这些新特性几天就可以掌握,一但掌握,效率会有很大的提高。其实我们涨工资也是涨的学习的钱,不学习终究会被淘汰,35 岁危机会提前来临。 From cdceff2cc34f910d9bd29651d8c6daad3bea6b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E8=82=87=E6=98=8E?= Date: Sun, 6 Jun 2021 23:24:15 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 觉得这行没什么用 --- docs/java/new-features/java8-common-new-features.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/java/new-features/java8-common-new-features.md b/docs/java/new-features/java8-common-new-features.md index 022a3bc9067..b914e5433e6 100644 --- a/docs/java/new-features/java8-common-new-features.md +++ b/docs/java/new-features/java8-common-new-features.md @@ -898,7 +898,6 @@ public void getDay() { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); //获取当前月第一天: Calendar c = Calendar.getInstance(); - c.add(Calendar.MONTH, 0); c.set(Calendar.DAY_OF_MONTH, 1); String first = format.format(c.getTime()); System.out.println("first day:" + first); @@ -1016,4 +1015,4 @@ System.out.println("本地时区时间: " + localZoned); - Optional - Date time-api -这些都是开发当中比较常用的特征。梳理下来发现它们真香,而我却没有更早的应用。总觉得学习 java 8 新特性比较麻烦,一致使用老的实现方式。其实这些新特性几天就可以掌握,一但掌握,效率会有很大的提高。其实我们涨工资也是涨的学习的钱,不学习终究会被淘汰,35 岁危机会提前来临。 \ No newline at end of file +这些都是开发当中比较常用的特征。梳理下来发现它们真香,而我却没有更早的应用。总觉得学习 java 8 新特性比较麻烦,一致使用老的实现方式。其实这些新特性几天就可以掌握,一但掌握,效率会有很大的提高。其实我们涨工资也是涨的学习的钱,不学习终究会被淘汰,35 岁危机会提前来临。 From c8a676100d0a9fdb2271e703f7c55fca8bec301d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E8=82=87=E6=98=8E?= Date: Sun, 6 Jun 2021 23:31:23 +0800 Subject: [PATCH 7/9] trim --- docs/java/new-features/java8-common-new-features.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/java/new-features/java8-common-new-features.md b/docs/java/new-features/java8-common-new-features.md index 022a3bc9067..7102e7d5688 100644 --- a/docs/java/new-features/java8-common-new-features.md +++ b/docs/java/new-features/java8-common-new-features.md @@ -934,7 +934,7 @@ public void getDayNew() { //当年最后一天 LocalDate lastday = today.with(TemporalAdjusters.lastDayOfYear()); //2021年最后一个周日,如果用Calendar是不得烦死。 - LocalDate lastMondayOf2021 = LocalDate.parse("2021-12- 31").with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY)); + LocalDate lastMondayOf2021 = LocalDate.parse("2021-12-31").with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY)); } ``` @@ -1016,4 +1016,4 @@ System.out.println("本地时区时间: " + localZoned); - Optional - Date time-api -这些都是开发当中比较常用的特征。梳理下来发现它们真香,而我却没有更早的应用。总觉得学习 java 8 新特性比较麻烦,一致使用老的实现方式。其实这些新特性几天就可以掌握,一但掌握,效率会有很大的提高。其实我们涨工资也是涨的学习的钱,不学习终究会被淘汰,35 岁危机会提前来临。 \ No newline at end of file +这些都是开发当中比较常用的特征。梳理下来发现它们真香,而我却没有更早的应用。总觉得学习 java 8 新特性比较麻烦,一致使用老的实现方式。其实这些新特性几天就可以掌握,一但掌握,效率会有很大的提高。其实我们涨工资也是涨的学习的钱,不学习终究会被淘汰,35 岁危机会提前来临。 From e2e340c7cb46199a345154353fbe8b7344e6cd42 Mon Sep 17 00:00:00 2001 From: guide Date: Mon, 7 Jun 2021 10:46:10 +0800 Subject: [PATCH 8/9] [docs]jvm --- README.md | 2 + ...40\350\275\275\350\277\207\347\250\213.md" | 4 + .../basis-of-authority-certification.md | 202 +++++++++++------- 3 files changed, 132 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index e8db97f4773..067cabfaef4 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ ### JVM (必看 :+1:) +JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle.com/javase/specs/jvms/se8/html/index.html) 和周志明老师的[《深入理解Java虚拟机(第3版)》](https://book.douban.com/subject/34907497/) (强烈建议阅读多遍!)。 + 1. **[Java 内存区域](docs/java/jvm/Java内存区域.md)** 2. **[JVM 垃圾回收](docs/java/jvm/JVM垃圾回收.md)** 3. [JDK 监控和故障处理工具](docs/java/jvm/JDK监控和故障处理工具总结.md) diff --git "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md" "b/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md" index c79de7df529..bf2811eb441 100644 --- "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md" +++ "b/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md" @@ -26,6 +26,10 @@ Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚 ![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/类加载过程.png) +详见:[jvm规范5.4](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4) 。 + +![](https://img-blog.csdnimg.cn/20210607102244508.png) + ### 加载 类加载过程的第一步,主要完成下面 3 件事情: diff --git a/docs/system-design/authority-certification/basis-of-authority-certification.md b/docs/system-design/authority-certification/basis-of-authority-certification.md index 22055861772..9a8a09f04b4 100644 --- a/docs/system-design/authority-certification/basis-of-authority-certification.md +++ b/docs/system-design/authority-certification/basis-of-authority-certification.md @@ -1,45 +1,75 @@ -## 1. 认证 (Authentication) 和授权 (Authorization)的区别是什么? +## 认证 (Authentication) 和授权 (Authorization)的区别是什么? 这是一个绝大多数人都会混淆的问题。首先先从读音上来认识这两个名词,很多人都会把它俩的读音搞混,所以我建议你先先去查一查这两个单词到底该怎么读,他们的具体含义是什么。 说简单点就是: -**认证 (Authentication):** 你是谁。 +- **认证 (Authentication):** 你是谁。 +- **授权 (Authorization):** 你有权限干什么。 -![](./images/basis-of-authority-certification/authentication.png) +稍微正式点(啰嗦点)的说法就是 : -**授权 (Authorization):** 你有权限干什么。 +- **Authentication(认证)** 是验证您的身份的凭据(例如用户名/用户 ID 和密码),通过这个凭据,系统得以知道你就是你,也就是说系统存在你这个用户。所以,Authentication 被称为身份/用户验证。 +- **Authorization(授权)** 发生在 **Authentication(认证)** 之后。授权嘛,光看意思大家应该就明白,它主要掌管我们访问系统的权限。比如有些特定资源只能具有特定权限的人才能访问比如 admin,有些对系统资源操作比如删除、添加、更新只能特定人才具有。 -![](./images/basis-of-authority-certification/authorization.png) +认证 : -稍微正式点(啰嗦点)的说法就是: +![](https://img-blog.csdnimg.cn/20210604160908352.png) -- **Authentication(认证)** 是验证您的身份的凭据(例如用户名/用户ID和密码),通过这个凭据,系统得以知道你就是你,也就是说系统存在你这个用户。所以,Authentication 被称为身份/用户验证。 -- **Authorization(授权)** 发生在 **Authentication(认证)** 之后。授权嘛,光看意思大家应该就明白,它主要掌管我们访问系统的权限。比如有些特定资源只能具有特定权限的人才能访问比如admin,有些对系统资源操作比如删除、添加、更新只能特定人才具有。 +授权: + +![](https://img-blog.csdnimg.cn/20210604161032412.png) 这两个一般在我们的系统中被结合在一起使用,目的就是为了保护我们系统的安全性。 -## 2. 什么是Cookie ? Cookie的作用是什么?如何在服务端使用 Cookie ? +## RBAC 模型介绍一下? + +系统权限控制最常采用的访问控制模型就是 **RBAC 模型** 。 + +**什么是 RBAC 呢?** + +RBAC 即基于角色的权限访问控制(Role-Based Access Control)。这是一种通过角色关联权限,角色同时又关联用户的授权的方式。 + +简单地说:一个用户可以拥有若干角色,每一个角色有可以被分配若干权限这样,就构造成“用户-角色-权限” 的授权模型。在这种模型中,用户与角色、角色与权限之间构成了多对多的关系,如下图 + +![RBAC](https://cdn.jsdelivr.net/gh/javaguide-tech/blog-images-3@main/11-9/RBAC.png) + +**在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。** + +本系统的权限设计相关的表如下(一共 5 张表,2 张用户建立表之间的联系): -![](./images/basis-of-authority-certification/cookie-sessionId.png) +![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/2020-11/%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AE%BE%E8%AE%A1-%E6%9D%83%E9%99%90.png) -### 2.1 什么是Cookie ? Cookie的作用是什么? +通过这个权限模型,我们可以创建不同的角色并为不同的角色分配不同的权限范围(菜单)。 -Cookie 和 Session都是用来跟踪浏览器用户身份的会话方式,但是两者的应用场景不太一样。 +![](https://cdn.jsdelivr.net/gh/javaguide-tech/blog-images-3@main/11-7/%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97.png) -维基百科是这样定义 Cookie 的:Cookies是某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密)。简单来说: **Cookie 存放在客户端,一般用来保存用户信息**。 +通常来说,如果系统对于权限控制要求比较严格的话,一般都会选择使用 RBAC 模型来做权限控制。 -下面是 Cookie 的一些应用案例: +## 什么是 Cookie ? Cookie 的作用是什么? -1. 我们在 Cookie 中保存已经登录过的用户信息,下次访问网站的时候页面可以自动帮你登录的一些基本信息给填了。除此之外,Cookie 还能保存用户首选项,主题和其他设置信息。 -2. 使用Cookie 保存 session 或者 token ,向后端发送请求的时候带上 Cookie,这样后端就能取到session或者token了。这样就能记录用户当前的状态了,因为 HTTP 协议是无状态的。 -3. Cookie 还可以用来记录和分析用户行为。举个简单的例子你在网上购物的时候,因为HTTP协议是没有状态的,如果服务器想要获取你在某个页面的停留状态或者看了哪些商品,一种常用的实现方式就是将这些信息存放在Cookie +![](./images/basis-of-authority-certification/cookie-SessionId.png) -### 2.2 如何在服务端使用 Cookie 呢? +`Cookie` 和 `Session` 都是用来跟踪浏览器用户身份的会话方式,但是两者的应用场景不太一样。 -这部分内容参考:https://attacomsian.com/blog/cookies-spring-boot, 更多如何在Spring Boot中使用Cookie 的内容可以查看这篇文章。 +维基百科是这样定义 `Cookie` 的: -**1)设置cookie返回给客户端** +> `Cookies` 是某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密)。 + +简单来说: **`Cookie` 存放在客户端,一般用来保存用户信息**。 + +下面是 `Cookie` 的一些应用案例: + +1. 我们在 `Cookie` 中保存已经登录过的用户信息,下次访问网站的时候页面可以自动帮你登录的一些基本信息给填了。除此之外,`Cookie` 还能保存用户首选项,主题和其他设置信息。 +2. 使用 `Cookie` 保存 `Session` 或者 `Token` ,向后端发送请求的时候带上 `Cookie`,这样后端就能取到 `Session` 或者 `Token` 了。这样就能记录用户当前的状态了,因为 HTTP 协议是无状态的。 +3. `Cookie` 还可以用来记录和分析用户行为。举个简单的例子你在网上购物的时候,因为 HTTP 协议是没有状态的,如果服务器想要获取你在某个页面的停留状态或者看了哪些商品,一种常用的实现方式就是将这些信息存放在 `Cookie` +4. ...... + +## 如何在项目中使用 Cookie 呢? + +我这里以 Spring Boot 项目为例。 + +**1)设置 `Cookie` 返回给客户端** ```java @GetMapping("/change-username") @@ -55,7 +85,7 @@ public String setCookie(HttpServletResponse response) { } ``` -**2) 使用Spring框架提供的`@CookieValue`注解获取特定的 cookie的值** +**2) 使用 Spring 框架提供的 `@CookieValue` 注解获取特定的 cookie 的值** ```java @GetMapping("/") @@ -64,7 +94,7 @@ public String readCookie(@CookieValue(value = "username", defaultValue = "Atta") } ``` -**3) 读取所有的 Cookie 值** +**3) 读取所有的 `Cookie` 值** ```java @GetMapping("/all-cookies") @@ -80,115 +110,139 @@ public String readAllCookies(HttpServletRequest request) { } ``` -## 3. Cookie 和 Session 有什么区别?如何使用Session进行身份验证? +更多关于如何在 Spring Boot 中使用 `Cookie` 的内容可以查看这篇文章:[How to use cookies in Spring Boot](https://attacomsian.com/blog/cookies-spring-boot。) 。 + +## Cookie 和 Session 有什么区别? -**Session 的主要作用就是通过服务端记录用户的状态。** 典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了。 +**`Session` 的主要作用就是通过服务端记录用户的状态。** 典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 `Session` 之后就可以标识这个用户并且跟踪这个用户了。 -**Cookie 数据保存在客户端(浏览器端),Session 数据保存在服务器端。相对来说 Session 安全性更高。如果使用 Cookie 的一些敏感信息不要写入 Cookie 中,最好能将 Cookie 信息加密然后使用到的时候再去服务器端解密。** +`Cookie` 数据保存在客户端(浏览器端),`Session` 数据保存在服务器端。相对来说 `Session` 安全性更高。如果使用 `Cookie` 的一些敏感信息不要写入 `Cookie` 中,最好能将 `Cookie` 信息加密然后使用到的时候再去服务器端解密。 -**那么,如何使用Session进行身份验证?** +**那么,如何使用 `Session` 进行身份验证?** -很多时候我们都是通过 SessionID 来实现特定的用户,SessionID 一般会选择存放在 Redis 中。举个例子:用户成功登陆系统,然后返回给客户端具有 SessionID 的 Cookie,当用户向后端发起请求的时候会把 SessionID 带上,这样后端就知道你的身份状态了。关于这种认证方式更详细的过程如下: +## 如何使用 Session-Cookie 方案进行身份验证? + +很多时候我们都是通过 `SessionID` 来实现特定的用户,`SessionID` 一般会选择存放在 Redis 中。举个例子: + +1. 用户成功登陆系统,然后返回给客户端具有 `SessionID` 的 `Cookie` +2. 当用户向后端发起请求的时候会把 `SessionID` 带上,这样后端就知道你的身份状态了。 + +关于这种认证方式更详细的过程如下: ![Session Based Authentication flow](./images/basis-of-authority-certification/Session-Based-Authentication-flow.png) 1. 用户向服务器发送用户名和密码用于登陆系统。 -2. 服务器验证通过后,服务器为用户创建一个 Session,并将 Session信息存储 起来。 -3. 服务器向用户返回一个 SessionID,写入用户的 Cookie。 -4. 当用户保持登录状态时,Cookie 将与每个后续请求一起被发送出去。 -5. 服务器可以将存储在 Cookie 上的 Session ID 与存储在内存中或者数据库中的 Session 信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。 +2. 服务器验证通过后,服务器为用户创建一个 `Session`,并将 `Session` 信息存储 起来。 +3. 服务器向用户返回一个 `SessionID`,写入用户的 `Cookie`。 +4. 当用户保持登录状态时,`Cookie` 将与每个后续请求一起被发送出去。 +5. 服务器可以将存储在 `Cookie` 上的 `SessionID` 与存储在内存中或者数据库中的 `Session` 信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。 + +使用 `Session` 的时候需要注意下面几个点: + +1. 依赖 `Session` 的关键业务一定要确保客户端开启了 `Cookie`。 +2. 注意 `Session` 的过期时间 + +画了个图简单总结了一下 `Session` 认证涉及的一些东西。 + +![](./images/basis-of-authority-certification/Session-cookie-intro.jpeg) -使用 Session 的时候需要注意下面几个点: +另外,Spring Session 提供了一种跨多个应用程序或实例管理用户会话信息的机制。如果想详细了解可以查看下面几篇很不错的文章: -1. 依赖Session的关键业务一定要确保客户端开启了Cookie。 -2. 注意Session的过期时间 +- [Getting Started with Spring Session](https://codeboje.de/spring-Session-tutorial/) +- [Guide to Spring Session](https://www.baeldung.com/spring-Session) +- [Sticky Sessions with Spring Session & Redis](https://medium.com/@gvnix/sticky-Sessions-with-spring-Session-redis-bdc6f7438cc3) -花了个图简单总结了一下Session认证涉及的一些东西。 +## 多服务器节点下 Session-Cookie 方案如何做? -![](./images/basis-of-authority-certification/session-cookie-intro.jpeg) +Session-Cookie 方案在单体环境是一个非常好的身份认证方案。但是,当服务器水平拓展成多节点时,Session-Cookie 方案就要面临挑战了。 -另外,Spring Session提供了一种跨多个应用程序或实例管理用户会话信息的机制。如果想详细了解可以查看下面几篇很不错的文章: +举个例子:假如我们部署了两份相同的服务 A,B,用户第一次登陆的时候 ,Nginx 通过负载均衡机制将用户请求转发到 A 服务器,此时用户的 Session 信息保存在 A 服务器。结果,用户第二次访问的时候 Nginx 将请求路由到 B 服务器,由于 B 服务器没有保存 用户的 Session 信息,导致用户需要重新进行登陆。 -- [Getting Started with Spring Session](https://codeboje.de/spring-session-tutorial/) -- [Guide to Spring Session](https://www.baeldung.com/spring-session) -- [Sticky Sessions with Spring Session & Redis](https://medium.com/@gvnix/sticky-sessions-with-spring-session-redis-bdc6f7438cc3) +**我们应该如何避免上面这种情况的出现呢?** -## 4.如果没有Cookie的话Session还能用吗? +有几个方案可供大家参考: + +1. 某个用户的所有请求都通过特性的哈希策略分配给同一个服务器处理。这样的话,每个服务器都保存了一部分用户的 Session 信息。服务器宕机,其保存的所有 Session 信息就完全丢失了。 +2. 每一个服务器保存的 Session 信息都是互相同步的,也就是说每一个服务器都保存了全量的 Session 信息。每当一个服务器的 Session 信息发生变化,我们就将其同步到其他服务器。这种方案成本太大,并且,节点越多时,同步成本也越高。 +3. 单独使用一个所有服务器都能访问到的数据节点(比如缓存)来存放 Session 信息。为了保证高可用,数据节点尽量要避免是单点。 + +## 如果没有 Cookie 的话 Session 还能用吗? 这是一道经典的面试题! -一般是通过 Cookie 来保存 SessionID ,假如你使用了 Cookie 保存 SessionID的方案的话, 如果客户端禁用了Cookie,那么Session就无法正常工作。 +一般是通过 `Cookie` 来保存 `SessionID` ,假如你使用了 `Cookie` 保存 `SessionID` 的方案的话, 如果客户端禁用了 `Cookie`,那么 `Session` 就无法正常工作。 -但是,并不是没有 Cookie 之后就不能用 Session 了,比如你可以将SessionID放在请求的 url 里面`https://javaguide.cn/?session_id=xxx` 。这种方案的话可行,但是安全性和用户体验感降低。当然,为了你也可以对 SessionID 进行一次加密之后再传入后端。 +但是,并不是没有 `Cookie` 之后就不能用 `Session` 了,比如你可以将 `SessionID` 放在请求的 `url` 里面`https://javaguide.cn/?Session_id=xxx` 。这种方案的话可行,但是安全性和用户体验感降低。当然,为了你也可以对 `SessionID` 进行一次加密之后再传入后端。 -## 5.为什么Cookie 无法防止CSRF攻击,而token可以? +## 为什么 Cookie 无法防止 CSRF 攻击,而 Token 可以? **CSRF(Cross Site Request Forgery)**一般被翻译为 **跨站请求伪造** 。那么什么是 **跨站请求伪造** 呢?说简单用你的身份去发送一些对你不友好的请求。举个简单的例子: -小壮登录了某网上银行,他来到了网上银行的帖子区,看到一个帖子下面有一个链接写着“科学理财,年盈利率过万”,小壮好奇的点开了这个链接,结果发现自己的账户少了10000元。这是这么回事呢?原来黑客在链接中藏了一个请求,这个请求直接利用小壮的身份给银行发送了一个转账请求,也就是通过你的 Cookie 向银行发出请求。 +小壮登录了某网上银行,他来到了网上银行的帖子区,看到一个帖子下面有一个链接写着“科学理财,年盈利率过万”,小壮好奇的点开了这个链接,结果发现自己的账户少了 10000 元。这是这么回事呢?原来黑客在链接中藏了一个请求,这个请求直接利用小壮的身份给银行发送了一个转账请求,也就是通过你的 Cookie 向银行发出请求。 -``` +```html 科学理财,年盈利率过万 ``` -上面也提到过,进行Session 认证的时候,我们一般使用 Cookie 来存储 SessionId,当我们登陆后后端生成一个SessionId放在Cookie中返回给客户端,服务端通过Redis或者其他存储工具记录保存着这个Sessionid,客户端登录以后每次请求都会带上这个SessionId,服务端通过这个SessionId来标示你这个人。如果别人通过 cookie拿到了 SessionId 后就可以代替你的身份访问系统了。 +上面也提到过,进行 `Session` 认证的时候,我们一般使用 `Cookie` 来存储 `SessionId`,当我们登陆后后端生成一个 `SessionId` 放在 Cookie 中返回给客户端,服务端通过 Redis 或者其他存储工具记录保存着这个 `SessionId`,客户端登录以后每次请求都会带上这个 `SessionId`,服务端通过这个 `SessionId` 来标示你这个人。如果别人通过 `Cookie` 拿到了 `SessionId` 后就可以代替你的身份访问系统了。 - Session 认证中 Cookie 中的 SessionId是由浏览器发送到服务端的,借助这个特性,攻击者就可以通过让用户误点攻击链接,达到攻击效果。 +`Session` 认证中 `Cookie` 中的 `SessionId` 是由浏览器发送到服务端的,借助这个特性,攻击者就可以通过让用户误点攻击链接,达到攻击效果。 -但是,我们使用 token 的话就不会存在这个问题,在我们登录成功获得 token 之后,一般会选择存放在 local storage 中。然后我们在前端通过某些方式会给每个发到后端的请求加上这个 token,这样就不会出现 CSRF 漏洞的问题。因为,即使有个你点击了非法链接发送了请求到服务端,这个非法请求是不会携带 token 的,所以这个请求将是非法的。 +但是,我们使用 `Token` 的话就不会存在这个问题,在我们登录成功获得 `Token` 之后,一般会选择存放在 local storage 中。然后我们在前端通过某些方式会给每个发到后端的请求加上这个 `Token`,这样就不会出现 CSRF 漏洞的问题。因为,即使有个你点击了非法链接发送了请求到服务端,这个非法请求是不会携带 `Token` 的,所以这个请求将是非法的。 -需要注意的是不论是 Cookie 还是 token 都无法避免跨站脚本攻击(Cross Site Scripting)XSS。 +需要注意的是不论是 Cookie 还是 Token 都无法避免 **跨站脚本攻击(Cross Site Scripting)XSS** 。 -> 跨站脚本攻击(Cross Site Scripting)缩写为 CSS 但这会与层叠样式表(Cascading Style Sheets,CSS)的缩写混淆。因此,有人将跨站脚本攻击缩写为XSS。 +> 跨站脚本攻击(Cross Site Scripting)缩写为 CSS 但这会与层叠样式表(Cascading Style Sheets,CSS)的缩写混淆。因此,有人将跨站脚本攻击缩写为 XSS。 -XSS中攻击者会用各种方式将恶意代码注入到其他用户的页面中。就可以通过脚本盗用信息比如cookie。 +XSS 中攻击者会用各种方式将恶意代码注入到其他用户的页面中。就可以通过脚本盗用信息比如 cookie。 -推荐阅读:[如何防止CSRF攻击?—美团技术团队](https://tech.meituan.com/2018/10/11/fe-security-csrf.html) +推荐阅读:[如何防止 CSRF 攻击?—美团技术团队](https://tech.meituan.com/2018/10/11/fe-security-csrf.html) -## 6. 什么是 Token?什么是 JWT?如何基于Token进行身份验证? +## 什么是 Token?什么是 JWT? -我们在上一个问题中探讨了使用 Session 来鉴别用户的身份,并且给出了几个 Spring Session 的案例分享。 我们知道 Session 信息需要保存一份在服务器端。这种方式会带来一些麻烦,比如需要我们保证保存 Session 信息服务器的可用性、不适合移动端(依赖Cookie)等等。 +我们在上一个问题中探讨了使用 Session 来鉴别用户的身份,并且给出了几个 Spring Session 的案例分享。 我们知道 Session 信息需要保存一份在服务器端。这种方式会带来一些麻烦,比如需要我们保证保存 Session 信息服务器的可用性、不适合移动端(依赖 Cookie)等等。 -有没有一种不需要自己存放 Session 信息就能实现身份验证的方式呢?使用 Token 即可!JWT (JSON Web Token) 就是这种方式的实现,通过这种方式服务器端就不需要保存 Session 数据了,只用在客户端保存服务端返回给客户的 Token 就可以了,扩展性得到提升。 +有没有一种不需要自己存放 Session 信息就能实现身份验证的方式呢?使用 Token 即可!JWT (JSON Web Token) 就是这种方式的实现,通过这种方式服务器端就不需要保存 Session 数据了,只用在客户端保存服务端返回给客户的 Token 就可以了,扩展性得到提升。 **JWT 本质上就一段签名的 JSON 格式的数据。由于它是带有签名的,因此接收者便可以验证它的真实性。** 下面是 [RFC 7519](https://tools.ietf.org/html/rfc7519) 对 JWT 做的较为正式的定义。 -> JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted. ——[JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) +> JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted. ——[JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) JWT 由 3 部分构成: -1. Header :描述 JWT 的元数据。定义了生成签名的算法以及 Token 的类型。 -2. Payload(负载):用来存放实际需要传递的数据 -3. Signature(签名):服务器通过`Payload`、`Header`和一个密钥(`secret`)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。 +1. **Header** : 描述 JWT 的元数据,定义了生成签名的算法以及 Token 的类型。 +2. **Payload** : 用来存放实际需要传递的数据 +3. **Signature(签名)** :服务器通过`Payload`、`Header`和一个密钥(`secret`)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。 + +## 如何基于 Token 进行身份验证? -在基于 Token 进行身份验证的的应用程序中,服务器通过`Payload`、`Header`和一个密钥(`secret`)创建令牌(`Token`)并将 `Token` 发送给客户端,客户端将 `Token` 保存在 Cookie 或者 localStorage 里面,以后客户端发出的所有请求都会携带这个令牌。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP Header 的 Authorization字段中:` Authorization: Bearer Token`。 +在基于 Token 进行身份验证的的应用程序中,服务器通过`Payload`、`Header`和一个密钥(`secret`)创建令牌(`Token`)并将 `Token` 发送给客户端,客户端将 `Token` 保存在 Cookie 或者 localStorage 里面,以后客户端发出的所有请求都会携带这个令牌。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP Header 的 Authorization 字段中:`Authorization: Bearer Token`。 ![Token Based Authentication flow](./images/basis-of-authority-certification/Token-Based-Authentication.png) 1. 用户向服务器发送用户名和密码用于登陆系统。 2. 身份验证服务响应并返回了签名的 JWT,上面包含了用户是谁的内容。 -3. 用户以后每次向后端发请求都在Header中带上 JWT。 +3. 用户以后每次向后端发请求都在 Header 中带上 JWT。 4. 服务端检查 JWT 并从中获取用户相关信息。 - 推荐阅读: -- [JWT (JSON Web Tokens) Are Better Than Session Cookies](https://dzone.com/articles/jwtjson-web-tokens-are-better-than-session-cookies) +- [JWT (JSON Web Tokens) Are Better Than Session Cookies](https://dzone.com/articles/jwtjson-web-Tokens-are-better-than-Session-cookies) - [JSON Web Tokens (JWT) 与 Sessions](https://juejin.im/entry/577b7b56a3413100618c2938) -- [JSON Web Token 入门教程](https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html) -- [彻底理解Cookie,Session,Token](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485603&idx=1&sn=c8d324f44d6102e7b44554733da10bb7&chksm=cea24768f9d5ce7efe7291ddabce02b68db34073c7e7d9a7dc9a7f01c5a80cebe33ac75248df&token=844918801&lang=zh_CN#rd) +- [JSON Web Token 入门教程](https://www.ruanyifeng.com/blog/2018/07/json_web_Token-tutorial.html) +- [彻底理解 Cookie,Session,Token](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485603&idx=1&sn=c8d324f44d6102e7b44554733da10bb7&chksm=cea24768f9d5ce7efe7291ddabce02b68db34073c7e7d9a7dc9a7f01c5a80cebe33ac75248df&Token=844918801&lang=zh_CN#rd) -## 7 什么是OAuth 2.0? +## 什么是 OAuth 2.0? -OAuth 是一个行业的标准授权协议,主要用来授权第三方应用获取有限的权限。而 OAuth 2.0是对 OAuth 1.0 的完全重新设计,OAuth 2.0更快,更容易实现,OAuth 1.0 已经被废弃。详情请见:[rfc6749](https://tools.ietf.org/html/rfc6749)。 +OAuth 是一个行业的标准授权协议,主要用来授权第三方应用获取有限的权限。而 OAuth 2.0 是对 OAuth 1.0 的完全重新设计,OAuth 2.0 更快,更容易实现,OAuth 1.0 已经被废弃。详情请见:[rfc6749](https://tools.ietf.org/html/rfc6749)。 -实际上它就是一种授权机制,它的最终目的是为第三方应用颁发一个有时效性的令牌 token,使得第三方应用能够通过该令牌获取相关的资源。 +实际上它就是一种授权机制,它的最终目的是为第三方应用颁发一个有时效性的令牌 Token,使得第三方应用能够通过该令牌获取相关的资源。 OAuth 2.0 比较常用的场景就是第三方登录,当你的网站接入了第三方登录的时候一般就是使用的 OAuth 2.0 协议。 -另外,现在OAuth 2.0也常见于支付场景(微信支付、支付宝支付)和开发平台(微信开放平台、阿里开放平台等等)。 +另外,现在 OAuth 2.0 也常见于支付场景(微信支付、支付宝支付)和开发平台(微信开放平台、阿里开放平台等等)。 微信支付账户相关参数: @@ -201,16 +255,12 @@ OAuth 2.0 比较常用的场景就是第三方登录,当你的网站接入了 - [OAuth 2.0 的四种方式](http://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html) - [GitHub OAuth 第三方登录示例教程](http://www.ruanyifeng.com/blog/2019/04/github-oauth.html) -## 8 什么是 SSO? +## 什么是 SSO? SSO(Single Sign On)即单点登录说的是用户登陆多个子系统的其中一个就有权访问与其相关的其他系统。举个例子我们在登陆了京东金融之后,我们同时也成功登陆京东的京东超市、京东家电等子系统。 -## 9.SSO与OAuth2.0的区别 - -OAuth 是一个行业的标准授权协议,主要用来授权第三方应用获取有限的权限。SSO解决的是一个公司的多个相关的自系统的之间的登陆问题比如京东旗下相关子系统京东金融、京东超市、京东家电等等。 - ## 参考 -- https://medium.com/@sherryhsu/session-vs-token-based-authentication-11a6c5ac45e4 +- https://medium.com/@sherryhsu/Session-vs-Token-based-authentication-11a6c5ac45e4 - https://www.varonis.com/blog/what-is-oauth/ - https://tools.ietf.org/html/rfc6749 From e4098a6bb2046899f4b952a8b6856fa895ff759a Mon Sep 17 00:00:00 2001 From: guide Date: Mon, 7 Jun 2021 14:49:20 +0800 Subject: [PATCH 9/9] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 067cabfaef4..eaf962f3c0a 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ > 1. **介绍**:关于 JavaGuide 的相关介绍请看:[关于 JavaGuide 的一些说明](https://www.yuque.com/snailclimb/dr6cvl/mr44yt) 。 > 2. **PDF版本** : [《JavaGuide 面试突击版》PDF 版本](#公众号) 。 > 3. **图解计算机基础** :[图解计算机基础 PDF 下载](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100021725&idx=1&sn=2db9664ca25363139a81691043e9fd8f&chksm=4ea19a1679d61300d8990f7e43bfc7f476577a81b712cf0f9c6f6552a8b219bc081efddb5c54#rd) 。 -> 4. **知识星球** : 简历指导/Java学习/面试指导/面试小册。欢迎加入[我的知识星球](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100015911&idx=1&sn=2e8a0f5acb749ecbcbb417aa8a4e18cc&chksm=4ea1b0ec79d639fae37df1b86f196e8ce397accfd1dd2004bcadb66b4df5f582d90ae0d62448#rd) 。星球内部更新的[《Java面试进阶指北 打造个人的技术竞争力》](https://www.yuque.com/docs/share/f37fc804-bfe6-4b0d-b373-9c462188fec7)这个小册的质量很高,专为面试打造。 -> 5. **面试专版** :准备面试的小伙伴可以考虑面试专版:[《Java 面试进阶指南》](https://xiaozhuanlan.com/javainterview?rel=javaguide) +> 4. **知识星球** : 简历指导/Java学习/面试指导/面试小册。欢迎加入[我的知识星球](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100015911&idx=1&sn=2e8a0f5acb749ecbcbb417aa8a4e18cc&chksm=4ea1b0ec79d639fae37df1b86f196e8ce397accfd1dd2004bcadb66b4df5f582d90ae0d62448#rd) 。 +> 5. **面试专版** :准备面试的小伙伴可以考虑面试专版:[《Java面试进阶指北 》](https://www.yuque.com/docs/share/f37fc804-bfe6-4b0d-b373-9c462188fec7) (质量很高,专为面试打造) > 6. **转载须知** :以下所有文章如非文首说明皆为我(Guide哥)的原创,转载在文首注明出处,如发现恶意抄袭/搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!⛽️