每日一读
不要害怕失败,因为失败并不代表你是一个失败者,而是一个正在努力追求成功的勇者。成功的道路上会有许多挑战和困难,但正是这些挑战塑造了你的坚韧和毅力。相信自己的能力,坚持不懈地追求梦想,即使进展缓慢也不要放弃。只有那些永不停歇的人才能最终达到辉煌的巅峰。
前言
最近有需求要开发一个新系统,正好用到了SpringSecurity框架来实现权限管理,索性就把这块相关的知识点复习复习,整理一下。
一、前置知识点
认证、授权、凭证
什么是认证(Authentication)?
认证(Authentication)是指确认一个实体(如用户、设备或系统)的身份真实性和合法性的过程。在计算机领域,认证通常用于验证用户的身份,确保只有授权的用户能够获得对特定系统、应用程序或资源的访问权限。
认证的目标是防止未经授权的访问和欺骗行为,确保系统的安全性和完整性。它通过验证用户提供的证据(也称为凭据)来验证其身份。常见的认证方式包括以下几种:
用户名和密码:用户提供一个唯一的用户名和与之相对应的密码进行验证。
邮箱发送登录链接:它通过向用户注册的电子邮箱发送包含特殊链接的电子邮件来实现。当用户点击该链接时,他们将被导向直接进入其账户而无需输入用户名和密码。
手机号验证码:通常通过向用户发送包含验证码的短信,用户在收到短信后输入其中的验证码进行验证。
双因素认证:除了用户名和密码外,还需要提供第二个因素,如短信验证码、指纹识别、智能卡等,提高身份验证的安全性。
生物特征认证:利用个体的生物特征信息(如指纹、虹膜、面部识别等)进行身份验证。
证书认证:使用公钥基础设施(PKI)技术,通过数字证书来验证身份。
单点登录(SSO):用户在一个系统中进行身份验证后,可以在其他关联系统中无需重新输入凭据而获得访问权限。
认证是确保系统、数据和用户安全的重要组成部分。它帮助保护个人隐私,防止未经授权的访问和恶意行为。在设计和实施认证机制时,需综合考虑安全性、用户体验和易于管理等方面的因素。
什么是授权(Authorization)?
授权(Authorization)是指对用户或系统身份的验证过程,以确定用户是否是请求访问某个资源或服务的合法用户。授权通常涉及使用用户名和密码、数字证书、生物识别等方式来验证用户的身份信息。在认证过程中,系统会比对用户提供的身份信息与已存储在系统中的数据进行匹配,如果成功匹配,则系统会授予用户相应的权限,否则就会拒绝用户的请求。
授权是保护计算机系统和网络安全的重要机制之一,它可以确保只有受信任的用户或系统才能够访问特定的资源,从而防止未经授权的访问或攻击。授权也是企业和组织实现网络安全管理和数据保护的关键环节之一。
什么是凭证(Credentialson)?
凭证(Authentication)是指用于验证用户身份的信息或数据。它是一种证明用户是合法用户的凭据,用于向系统或服务提供商证明用户的身份以获取访问权限。
凭证可以是不同类型的信息,例如:
用户名与密码:这是最常见的凭证形式,用户通过提供正确的用户名和与之对应的密码进行身份验证。
数字证书:数字证书是一种包含有关用户或实体身份信息及相关加密密钥的数字文件。通过验证数字证书的有效性,可以确保用户或实体的身份。
双因素验证:双因素验证需要用户提供两种不同类型的凭证来验证身份,例如结合密码和手机短信验证码、指纹识别等方式。
生物识别信息:生物识别信息,如指纹、面部识别、虹膜扫描等,可以作为凭证来验证用户的身份。
无论使用哪种类型的凭证,其目的都是确保只有合法的用户可以获得访问权限,保护系统和数据的安全性。
二、什么是Cookie?
了解Cookie
首先需要明白的是http协议是一个无状态协议,客户端向服务器端发送请求、服务端响应给客户端就这样就结束了,但是下次发请求的客户端是谁呢?不知道...这种背景下,就产生了Cookie,Cookie 最开始被设计出来是为了弥补HTTP在状态管理上的不足。
Cookie存储在客户端
Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。因此,服务端脚本就可以读、写存储在客户端的Cookie 的值。
Cookie是不可跨域的
每个 cookie 都会绑定单一的域名(绑定域名下的子域都是有效的),无法在别的域名下获取使用,同域名不同端口也是允许共享使用的。
Cookie属性:有效期和作用域
cookie默认的有效期很短,它只在Web浏览器的会话期间持续有效。一旦用户关闭浏览器,cookie中保存的数据就会丢失。需要注意的是,与sessionStorage不同,cookie的作用域不限于单个浏览器窗口,它的有效期与整个浏览器进程保持一致。如果希望延长cookie的有效期,可以通过设置max-age属性来实现。设置有效期后,浏览器会将cookie数据存储在文件中,并在指定的有效期过后才会删除该文件。
和localStorage、sessionStorage类似,cookie的作用域是由文档源和文档路径来确定的。可以通过设置cookie的path和domain属性来配置cookie的作用域。默认情况下,cookie与创建它的Web页面相关,并且对于与该Web页面位于同一目录或子目录的其他Web页面可见。举个例子,如果一个Web页面 http://www.liuxs.com/info/index.html 创建了一个cookie,那么该cookie将对 http://www.liuxs.com/info/order.html 页面和 http://www.liuxs.com/info/widgets/index.html 页面都可见,但对 http://www.liuxs.com/about.html 页面不可见。换句话说,cookie的作用域限定在相同路径或子路径下的Web页面。
默认情况下,cookie的作用域受到文档源的限制。然而,在某些情况下,大型网站可能希望实现子域之间的cookie共享。例如,order.example.com 域的服务器希望能够读取 catalog.example.com 域设置的cookie值。为了实现这个目的,可以将 catalog.example.com 域下的cookie的path属性设置为"/",将domain属性设置为".example.com"。这样一来,该cookie就对于所有在 catalog.example.com、order.example.com 以及任何其他 example.com 域下的服务器都是可见的。如果没有为cookie设置域属性,那么domain属性的默认值是当前Web服务器的主机名。值得注意的是,cookie的域只能设置为当前服务器的域。
Cookie的重要属性
| 属性 | 说明 |
| name=value | 键值对,设置 Cookie 的名称及相对应的值,都必须是字符串类型(name 不区分大小写)如果值为 Unicode 字符,需要为字符编码。如果值为二进制数据,则需要使用 BASE64 编码。 |
| domain | 指定 Cookie 所属域名,默认是当前域名 |
| path | 指定 Cookie 在哪个路径(路由)下生效,默认是 '/'。 如果设置为 abc,则只有 abc 下的路由可以访问到该 Cookie ,如:/abc/read。 |
| expires | 过期时间(GMT时间格式),在设置的某个时间点后该 Cookie 就会失效。 如果客户端和服务器时间不一致,使用expires就会存在偏差。 一般浏览器的 Cookie 都是默认储存的,当关闭浏览器结束这个会话的时候,这个 Cookie 也就会被删除 |
| max-age | Cookie 有效期,单位秒。如果为正数,则该 Cookie 在 maxAge 秒后失效。如果为负数,该 Cookie 为临时 Cookie ,关闭浏览器即失效,浏览器也不会以任何形式保存该 Cookie 。如果为 0,表示删除该 Cookie 。默认为 -1。 - 优先级高于 expires |
| HttpOnly | 如果给某个 Cookie 设置了 httpOnly 属性,则无法通过 JS 脚本 读写该 Cookie 的信息,但还是能通过 Application 中手动修改 Cookie ,所以只是在一定程度上可以防止 CSRF 攻击,不是绝对的安全 |
| secure | 该 Cookie 是否仅被使用安全协议传输。安全协议有 HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。 当 secure 值为 true 时,Cookie 在 HTTP 中是无效的。 |
domain 属性的使用
在没有设置 domain 的情况下,默认 cookie 只设置在当前域名下。我们在设置 cookie 时,也可以设置 domain 属性,这个 domain 只能是当前域名的上级域名,这样上级域名相同的网站就都能读取到这个 cookie 了。
比如:我在网站 aa.liuxs.com 下设置 cookie:"myName=liuxs; domain=.liuxs.com",这样在 bb.liuxs.com 下也能读取到 myName=liuxs。
Cookie的局限性
Chrome和Safari没有做硬性限制
Firefox最多50个cookie
IE7和之后的版本最后可以有50个cookie
IE6或更低版本最多20个cookie
RFC 2965标准不允许浏览器保存超过300个cookie,为每个Web服务器保存的cookie数不能超过20个(是对整个服务器而言,而不仅仅指服务器上的页面和站点),而且,每个cookie保存的数据不能超过4KB。实际上,现代浏览器允许cookie总数超过300个,但是部分浏览器对单个cookie大小仍然有4KB的限制。
三、什么是Session?
session是一种用于在Web服务器和浏览器之间跟踪客户端状态的机制。在一个Web会话中,当用户首次访问服务器时,服务器会为该用户创建一个唯一的会话ID,并将该会话ID与用户相关的信息保存在服务器端。这些信息可以包括用户的登录状态、购物车内容等等。同时,服务器还会将该会话ID发送给客户端(通常是通过cookie的方式),以便客户端能够在接下来的请求中将该会话ID发送回服务器。在接下来的会话中,每个由同一客户端发起的请求都会携带该会话ID。服务器利用该会话ID来识别请求的来源,从而能够获取之前保存的与该会话ID相关的信息,完成相关操作。当用户关闭浏览器或者退出登录时,服务器会销毁与该会话ID相关的信息,该会话也随之结束。总之,session机制为Web应用程序提供了一种可靠的方式来跟踪客户端状态,使得Web应用程序能够更好地管理和维护客户端的状态信息。

Session 是基于 Cookie 实现的,Session 存储在服务器端,S、essionId 会被存储到客户端的Cookie 中。
根据以上流程可知,SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。
四、Cookie 和 Session 的区别
安全性:Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。
存取值的类型不同:Cookie 只支持存字符串数据,Session 可以存任意数据类型。
有效期不同:Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
存储大小不同:单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。
五、什么是Token
Token是一种用于身份验证和授权的令牌。在Web应用程序中,Token通常是服务器生成并发送给客户端(如浏览器)的一个字符串,客户端在接下来的请求中将该令牌包含在请求中,以证明其身份或获取特定的权限。
Token可以分为不同类型,最常见的是JSON Web Token(JWT)。JWT由三个部分组成:头部(Header)、载荷(Payload)和签名(Signature)。头部通常包含关于Token的元数据,如加密算法等。载荷则用于存储一些自定义的信息,比如用户ID、角色等。签名部分用来验证Token的真实性,确保Token没有被篡改。当然还有简单的token,下面说明
在使用Token进行身份验证时,客户端在登录认证成功后会收到一个Token,之后每次发送请求时都需要将Token放在请求的头部、查询参数或者Cookie中传递给服务器。服务器在接收到请求后,通过验证Token的有效性和合法性来判断用户的身份,并根据Token中携带的权限信息进行授权操作。
相比传统的基于Session的身份验证机制,Token具有以下优势:无状态、可扩展、跨域支持等。Token的使用可以提高系统的安全性和可伸缩性,广泛应用于现代Web应用程序和API的身份验证和授权场景中。
简单的token组成 : uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)
特点:
服务端无状态化、可扩展性好
支持移动端设备
安全
token 完全由应用管理,所以它可以避开同源策略
Access Token
Access Token 的身份验证流程:

客户端通过提供用户名和密码向服务端发送登录请求。
服务端接收到请求后,进行用户名和密码的验证。
验证成功后,服务端生成一个令牌(token)并将其发送给客户端。
客户端接收到token后,将其存储,例如保存在localStorage中。
每次客户端发起请求时,需要将token放入请求头(Header)中传递给服务端。
服务端接收到请求后,会验证客户端请求中携带的token。
如果token验证成功,服务端将响应请求并返回相应的数据给客户端。
Refresh Token
还有一种token那就是Refresh Token,Refresh token是一种用于刷新访问令牌(access token)的特殊令牌。即使没有refresh token,也可以刷新access token,但每次刷新都需要用户输入登录的用户名和密码,这样会非常繁琐。而有了refresh token,可以减少这种麻烦。客户端可以直接使用refresh token来更新access token,无需用户进行额外的操作。通过使用refresh token进行刷新,客户端可以维持用户的会话状态,并获取新的有效的access token,从而持续地访问受保护的资源,提升用户体验和安全性。

Access Token的有效期相对较短,当Access Token因为过期而失效时,可以使用Refresh Token来获取新的Token。但如果Refresh Token也失效了,用户就需要重新登录。
Refresh Token以及它的过期时间存储在服务器的数据库中。只有在请求新的Access Token时,才会对Refresh Token进行验证。这种验证不会对业务接口的响应时间产生影响,并且不需要将Refresh Token像Session一样一直保持在内存中,以适应大量请求的情况。通过这种方式,可以保护用户的身份和安全,同时提供方便的访问令牌刷新机制。
六、Token 和 Session 的区别
Token和Session是两种常见的身份验证和会话管理机制,它们之间有以下区别:
存储位置:Token通常是由服务器生成并发送给客户端,存储在客户端(比如浏览器的localStorage或cookie)中。而Session则是服务器端存储用户会话状态的一种机制,通常存储在服务器的内存或数据库中。
无状态 vs 有状态:Token是无状态的,每个请求都包含完整的用户身份信息和权限,服务器无需在后续请求中保留任何关于用户的状态。而Session是有状态的,服务器需要在会话期间维护用户的状态信息,通常通过一个唯一的session ID来识别不同的会话。
扩展性:由于Token是无状态的,服务器可以将身份验证和授权逻辑分离,使得服务器更容易进行横向扩展。而Session的有状态特性使得负载均衡和横向扩展变得更加复杂,因为需要将会话状态共享或存储在多个服务器上。
安全性:使用Token时,可以使用各种加密算法来保护令牌的安全性,并且令牌中可以包含有限的过期时间和权限范围,从而提供更细粒度的访问控制。相比之下,Session在服务器端存储且不直接暴露给客户端,可以更好地控制和保护用户的会话数据。
总体而言,Token适用于分布式系统和无状态的API身份验证,提供了更高的扩展性和灵活性。而Session适用于传统的服务器端应用程序,提供了更强的安全性和状态管理能力。选择哪种机制取决于应用的需求和特定的场景。
七、什么是JWT
JWT是JSON Web Token的缩写,是一种用于身份验证和授权的开放标准。它是一种轻量级的安全令牌,由三部分组成:头部(Header)、载荷(Payload)和签名(Signature),这三部分使用点号进行分隔。
头部(Header):头部通常由两部分组成,令牌的类型(例如JWT)和所使用的签名算法(例如HMAC SHA256或RSA)。头部也可以包含其他可选信息。
载荷(Payload):载荷是令牌的主要内容,包含了一些声明信息,比如用户的身份、权限等相关数据。载荷可以添加自定义的声明,也可以使用已定义的一些标准声明,如用户ID、过期时间等。
签名(Signature):签名是使用私钥对头部和载荷进行加密生成的一串字符串,用于验证令牌的完整性和真实性。服务器在接收到令牌后,可以使用公钥对签名进行解密并验证令牌是否被篡改。
JWT的使用方式非常灵活,它可以作为身份验证信息被传输,在客户端和服务器之间进行安全的通信。通过使用数字签名,可以确保令牌的真实性和完整性。JWT还可以使用过期时间来控制令牌的有效期,从而提供了一种无状态的身份验证机制。
JWT的优点包括跨语言、易于传输、可自包含性以及扩展性。然而,需要注意的是,由于JWT是基于令牌的验证方式,因此需要保护好令牌的安全性,防止令牌被盗用。

用户输入用户名和密码进行登录后,如果通过了服务端的认证,服务端会生成一个JWT令牌并返回给客户端。
客户端收到令牌后,通常会将其保存在本地,一般使用localStorage或cookie来存储。
当用户需要访问受保护的路由或资源时,客户端需要在请求头的Authorization字段中以Bearer模式添加JWT令牌,形式如:Authorization: Bearer <token>。
服务端的受保护路由会对请求头中的Authorization字段中的JWT信息进行检查。如果检查合法,则允许用户执行相应的操作。
JWT是自包含的,内部包含了一些会话信息,因此可以减少需要查询数据库的需求,提升系统性能。
由于JWT不使用Cookie,所以API服务可以在任何域名下提供,无需担心跨域问题。
JWT的认证机制是一种无状态的机制,因为用户的状态不再存储在服务端的内存中,而是通过JWT中的信息进行验证,这样使得系统更加可扩展和可靠。
jwtToken的数据结构:
jwtToken的数据结构类似于以下这种
它是一个很长的字符串,中间用点(.)分隔成三个部分。JWT 的三个部分依次如下:
Header(头部)
Payload(负载)
Signature(签名

Token和Jwt的区别
Token和JWT(JSON Web Token)是两个不同的概念,可以从以下几个方面进行区别阐述:
1.格式和结构:
Token:通常是一个字符串,由服务端生成,用于表示用户的身份或权限。
JWT:是一种特定格式的Token,采用JSON格式进行编码,由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
2.安全性和可验证性:
Token:普通的Token可能只是一个随机生成的字符串,验证时需要在服务端进行数据库或缓存查询,以验证其合法性。
JWT:JWT通过添加数字签名(Signature)来保证其完整性和安全性,在服务端验证时可以直接解析并验证签名,无需再进行数据库查询,提高了验证的效率。
3.扩展性和传递性:
Token:普通的Token只能用于表示身份或权限等基本信息,无法携带其他自定义的数据。
JWT:JWT的载荷部分可以携带自定义的数据,如用户ID、角色等,具有更好的扩展性。同时,JWT采用Base64编码,可以在请求头或URL中传递,方便使用和传递。
4.生命周期和存储方式:
Token:普通的Token可以有不同的生命周期设置,例如设置过期时间或使用刷新令牌来延长有效期。Token通常存储在服务端的数据库或缓存中。
JWT:JWT可以通过设置失效时间(exp)来控制其生命周期,也可以使用刷新令牌机制延长有效期。JWT一般采用客户端存储(如localStorage或cookie),不需要额外的服务端存储。
总的来说,JWT是一种基于JSON格式的安全、可验证、扩展性强的Token实现,提供了更好的传递性和无需服务端查询的验证方式。而普通的Token可能只是一个代表身份或权限的字符串,验证时需要依赖服务端进行查询验证。
使用Session时需要注意的事项
会话的创建和销毁:合理的创建和销毁会话,确保会话的有效性和安全性。
分布式环境:如果系统部署在多个服务器上,则需要考虑如何在多个服务器之间共享会话信息。
存储和传输开销:会话数据的存储和传输可能涉及到一定的性能开销,需要权衡数据量和性能需求。
用户注销和退出:提供合适的注销和退出机制,确保用户可以有效地结束会话并清除相关信息。
强制注销:在必要情况下,有能力强制性地注销会话,以应对安全漏洞或恶意行为。
使用Jwt时需要注意的事项
1.验证签名:
JWT包含了明文内容和签名,应该始终验证签名以确保内容的完整性和真实性。
可以使用公钥和私钥对JWT进行加密和解密,并确保只有持有私钥的机构可以签名和验证JWT。
2.避免敏感信息:
不应该将敏感信息存储在JWT的明文中,而应该使用加密或哈希等技术来保护数据的机密性。
客户端也应该避免在不安全的环境中存储敏感信息,如Cookie或本地存储等。
3.控制过期时间:
JWT具有过期时间,应该设置适当的过期时间以确保安全性。
过期时间过短可能导致频繁的重新验证,过期时间过长可能导致安全风险。开发人员需要根据实际需求来设置合适的过期时间。
4.避免重复使用:
始终生成新的JWT,避免重复使用同一个JWT。如果JWT泄漏或被其他人劫持,则可以立即使其失效。
5.防止CSRF攻击:
JWT不提供防止跨站请求伪造(CSRF)攻击的保护,需要使用其他技术(如同步令牌、cookie、referrer检查等)来防止CSRF攻击。
6.避免缓存:
JWT包含敏感信息,不应该被浏览器缓存或存储在客户端的本地存储中。
在前端JavaScript代码中使用JWT时,应该避免使用localStorage、sessionStorage等缓存机制。
结束
ok了家人们,今天的分享到此结束,看到这想必你应该觉的文章写的挺不错的,不妨点个关注,我拉你进技术分享群,一起讨论更多的技术,分享更多的知识!
晚安!!




