Java Web —— 认证&授权
Related Glossary
认证(Authentication):通俗讲认证即验证用户是账号的主人。指验证用户的身份,确保用户是其声称的身份。常见的认证方式包括用户名和密码登录、邮箱或手机验证码、生物识别(如指纹或面部识别)等。这一过程确保系统识别用户并为其提供适当的访问权限。
授权(Authorization):指控制用户能够访问的资源和可以执行的操作。用户在通过身份验证后,授权系统决定该用户可以使用哪些资源、数据或执行哪些操作。授权机制通常基于用户的角色、权限组或具体的权限设置。此外,授权还包括用户允许第三方应用访问其某些资源(如头像、昵称、地区等信息)的权限授予。
凭证(Credentials):认证过程中用户提供的验证信息,用于证明其身份。常见的凭证包括用户名/密码组合、API 密钥、访问令牌等。凭证验证通过后,系统确认用户身份并允许其继续操作。
单点登录(Single Sign-On,SSO):单点登录,指在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
例如你登录网易账号中心(https://reg.163.com/ )之后访问以下站点都是登录状态。
- 网易直播 https://v.163.com
- 网易博客 https://blog.163.com
- 网易花田 https://love.163.com
- 网易考拉 https://www.kaola.com
- 网易 Lofter http://www.lofter.com
Cookie
在 Web 开发中,Cookie、Token 和 Session 这三者常常被一起讨论,特别是在会话管理和身份验证的语境下
- Cookie 是一种客户端与服务器之间的键值对(Key-Value)信息载体。浏览器会将 Cookie 存储在用户的设备上,并在后续请求中自动发送给服务器。Cookie 可用于保存会话信息、用户偏好、身份认证令牌等
- Session 是服务器端保存用户状态的一种机制
- Token 是一种用于身份验证的凭证,通常用于无状态的身份验证系统
总结:Cookie 是信息载体,Session&Token 为信息本身
Cookie 作为一种存储方法,用于在客户端存储少量的 KV 数据。这些数据可以有下面这些属性:
Name
:Cookie 的名称,用于标识不同的 Cookie。创建后名称不可更改Value
:Cookie 的值,即存储的具体数据。如果值为 Unicode 字符,需要为字符编码。如果为二进制数据,则需要使用 BASE64 编码maxAge
Cookie 失效时间(seconds)。正数表示该 Cookie 在 maxAge 秒后失效。负数表示 Cookie 在关闭浏览器后就失效。0
表示删除该 Cookie;默认值-1
Domain
:指定 Cookie 可以被哪些domain
下的页面访问。例如,设置为.example.com
表示所有子域名下的页面都可以访问该 Cookie。起始字符必须为.
Path
:指定 Cookie 可以被哪些路径下的页面访问。例如,设置为/admin
表示只有/admin
路径下的页面可以访问该 Cookie。secure
,httpOnly
:用于提高安全性的字段- …
chromium 内核的浏览器可以按 F12 进入 devtools,在 application 可以查看网站存储的 cookie,localstorage,session storage 等一系列数据。
工作原理
- 当用户访问一个网站时,服务器可以通过 HTTP 响应报文中添加 Set-Cookie 头,将 Cookie 数据发送给用户的浏览器。
- 浏览器会将这些 Cookie 存储起来,并在后续请求同一网站时通过 Cookie 请求头自动发送回服务器。
应用场景
Cookie 用途广泛,以下是常见的应用场景:
- 会话管理:Cookie 可用于存储用户的 Session ID,帮助服务器在用户访问多个页面时维持会话。
- 偏好设置:网站可以通过 Cookie 保存用户的语言选择、主题偏好等信息。
- 身份验证:浏览器可以通过存储 Token(如 JWT 或 OAuth 令牌)在 Cookie 中,实现自动发送身份验证信息给服务器。
- 跟踪行为:记录分析用户行为
Other Storage Method
实际上,浏览器有很多存储机制,以 LocalStorage 为例,它相比 Cookie 可以存储更多的信息。此外,客户端也不局限于 Web 网页,部分小程序,移动端 app 不支持 cookie,此时就需要使用其它存储方式。
存储方式 | 类型 | 描述 | 存储限制 | 持久性 |
---|---|---|---|---|
Cookies | 标准 | 由浏览器存储的小块数据,随每次 HTTP 请求一起发送回服务器。主要用于会话管理、身份验证和跟踪用户行为。 | 每个 Cookie 大约 ~4KB | 通常设置有到期日期;可以是会话性或持久性。 |
Local Storage | 标准 | 浏览器中的键值对存储,即使浏览器关闭后数据仍然存在。适合存储需要跨会话保持的小量数据。 | 每个域名大约 ~5-10MB | 持久性,直到明确删除为止。 |
Session Storage | 标准 | 类似于 Local Storage,但数据仅在页面会话期间可用。当页面或标签关闭时数据将被清除。 | 每个域名大约 ~5-10MB | 会话性。 |
IndexedDB | 标准 | 一种用于存储大量结构化数据(包括文件和二进制数据)的低级 API。提供支持事务、搜索和索引的强大解决方案。 | 取决于浏览器实现;通常为几个 GB | 持久性,直到明确删除为止。 |
WebSQL | 非标准(已弃用) | 使用 SQL 语法的数据库存储机制。它曾被设计为 Local Storage 的更强大替代品,但由于 IndexedDB 的出现而被弃用。 | 类似于 IndexedDB | 持久性,直到明确删除为止。 |
File System Access API | 非标准(新兴标准) | 允许 Web 应用程序读取和写入本地文件系统,为管理用户设备上的文件提供了强大的方式。 | 取决于用户权限和浏览器实现。 | 持久性,直到应用程序或用户明确删除。 |
Session
HTTP 是一个无状态协议(stateless),Client 每次发出请求都是相互独立的,新的请求无法得知上一次请求所包含的状态数据。
假设 Server 端某个网页(下面将其称作 Private Page A)需要用户登录后才可以访问。Client 首先发起 HTTP Request 完成登录后,然后在下一个 HTTP Request 中发起对 Private Page A 资源的请求。但鉴于 HTTP 是无状态的,Server 端收到该请求时,无法得知用户是否已经登录,从而无法确定是否可以访问 Private Page A。
针对该问题,有几种解决方案。Cookie+Session 便是其中之一
Session 工作流程
- 用户登录成功后,服务器为用户创建一个 Session,并给该 Session 生成一个唯一的 Session ID;服务器可以使用
SetCookie
将 Session ID 保存在 Cookie 中,通过响应报文将 Session ID 发送给客户端;
Java Servlet 规范规定,会话跟踪 cookie 的名称应为JSESSIONID - Session 数据会被存储在服务器端,可以放在内存、数据库或文件中。常用的方式是将 Session ID 作为键,与对应的 Session 用户身份数据进行关联
- 当用户发来一个新的 HTTP Request 时,浏览器会在报文中携带 Session ID(存储在 Cookie 中),Server 端根据 Session ID 查找对应的 Session 数据,从而获得用户的状态信息(比如登录状态,购物车内容,个人设置等等)。并可以根据业务需求对其中的状态信息执行增删改查。
- Session 会设置有效期限。一般通过设置一个固定的时间,或者在一定时间内没有用户活动时会将 Session 标记为过期。当 Session 过期时,服务器会销毁对应的 Session 数据,释放内存或其他资源。
Session 的管理
Token
令牌 Token 是一种用于身份验证的凭证,通常用于无状态的身份验证系统。Token 可以是 JSON Web Token(JWT)或 OAuth 中的访问令牌。与 Session 机制不同,Token 在认证过程中不需要服务器端存储用户状态,而是通过生成一段加密的字符串来标识和验证用户身份,减少了服务器的负担。这种机制在微服务架构、跨域认证以及移动应用中得到了广泛的应用。
Token 的特点:
- Token 可存储在客户端的 Cookie、Local Storage 或 Session Storage 中。
- 与 Session 不同,Token 可以在服务器无状态的情况下完成身份验证。
- Token 常用于分布式系统,尤其是需要跨多个服务进行验证的场景。
- 相比于 Session,Token 可以放置CSRF(Cross Site Request Forgery)攻击,但两者都不能防止XSS(Cross Site Scripting)攻击,详见前端安全系列(二):如何防止 CSRF 攻击?
Token 类型
- 访问 Token(Access Token):用于访问受保护的资源,一般有较短的有效期。
- 刷新 Token(Refresh Token):用于获取新的访问 Token,通常有较长的有效期或不设置有效期。
Token 工作流程
- 用户登录:用户通过用户名、密码等方式发送登录请求给服务器。
- 生成 Token:服务器验证用户身份成功后,生成一个 Token,并将其返回给客户端。
- 客户端存储 Token:客户端(通常是浏览器或移动应用)将 Token 存储在 localStorage、sessionStorage 或 Cookie 中。
- 携带 Token 访问资源:客户端每次向服务器发起请求时,将 Token 放入请求头中(通常使用
Authorization: Bearer <token>
格式)(也可以 post 请求的数据体或 cookie 里,但存放在使用 cookie 里可能存在) - 服务器验证 Token:服务器接收到请求后,验证 Token 的有效性,若有效则处理请求并返回响应。
JWT
JWT (JSON Web Token) 是一种常见的 Token 格式,由三部分组成,用.
分隔,形如xxxxx.yyyyy.zzzzz
- Header(头部):通常由两部分组成:令牌的类型(JWT)和使用的签名算法(如 HMAC SHA256 或 RSA)。
- Payload(负载):存储声明(Claims),声明分为 registered claims, public claims, private claims 三种。
- iss(Issuer):签发者
- sub(Subject):面向的用户
- exp(Expiration Time):过期时间
- aud(Audience):接收方
- nbf(Not Before):生效时间
- iat(Issued At):签发时间
- jti(JWT ID): 标识符
- Signature(签名):确保 JWT 的完整性,防止其在传输过程中被篡改。签名部分是对 Header 和 Payload 的签名,通常使用 HMAC SHA-256 或 RSA 算法。签名的生成过程如下:
secret:用于生成签名的密钥,通常为服务器端定义的,不能泄露给客户端。
算出签名后,将 header,payload,signature 三者进行 Base64Url 编码,拼接在一起,用.
分隔,得到最终的 JWT 字符串。
Pros
- 跨域支持:JWT 是无状态的,令牌中携带了用户信息,因此任何服务器都可以验证 JWT,无需服务器之间共享 Session。
- 安全性:JWT 采用签名机制(通常使用 HMAC 或 RSA)保证令牌的完整性,防止数据被篡改;一些复杂的 token 机制中,一个 token 令牌可以包含地理位置信息,网络信息,客户端属性,包括浏览器指纹,即便 token 泄漏,其他人拿着这个 token 也难以请求成功;此外双 token 方案也能一定程度上保证安全性(access token+refresh token)
- 高效传输:JWT 采用了 Base64Url 编码,将数据压缩为较短的字符串格式,可以安全地放入 URL 或 HTTP 头中。
Cons - Payload 可解码:虽然 JWT 的 Payload 是签名的,但它是可读的(JWT 只进行了编码而未进行加密),所以敏感信息不应放入 Payload 中;如果需存储敏感信息,应对敏感内容进行加密
Ref
HTTP cookie - wikipedia
Using HTTP cookies - HTTP|MDN
Cookies vs. LocalStorage: Storing Session Data and Beyond
京东面试:说说 Cookie、Session 和 Token 的区别?
What is a JSESSIONID in Java
jwt.io-Introduction to JSON Web Tokens
JSON Web Token 入门教程
JavaGuide-多服务器节点下 Session-Cookie 方案如何做?
前端安全系列(二):如何防止 CSRF 攻击?
Cookie、Session、Token、JWT 一次性讲完-bilibili 织点代码
Java Web —— 认证&授权