axios封装
对Axios的理解
Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 node.js,它提供了简洁的 API 和拦截器等功能,非常适合进行封装以应对复杂的请求场景。下面展示一个简单的 Axios 封装示例,包括基础配置、请求拦截器、响应拦截器以及如何使用。
安装 Axios
首先,你需要确保项目中已经安装了 Axios。如果还未安装,可以通过以下命令安装:
1 | npm install axios |
Axios 封装
下面的代码示例展示了如何封装 Axios,包括配置基本的请求信息、添加请求拦截器和响应拦截器。
1 | import axios from 'axios'; |
使用封装后的 Axios
封装完成后,你可以在项目的任何地方通过导入封装后的实例来发起请求:
1 | import request from './path/to/axios'; // 路径根据实际情况修改 |
通过这种方式,你可以轻松地在整个项目中复用配置好的 Axios 实例,而不必每次请求都重复设置。此外,通过拦截器,你可以在请求发送前后执行一些通用处理,如设置认证信息、处理错误等,大大增强了代码的可维护性和复用性。
理解JWT的组成
JSON Web Token(JWT)是一种开放标准(RFC 7519),用于安全地在两方之间传输信息作为JSON对象。它在Web应用中广泛用于无状态认证机制,特别是在单点登录(SSO)中。JWT的设计目的是可以通过网络传输并且可以自验证和自包含,这意味着它们携带了所有必要的信息,以验证数据的完整性和真实性。一个JWT实际上由三个主要部分组成,它们之间用点(.)分隔,形式为xxxxx.yyyyy.zzzzz
。这三部分分别是:
Header(头部)
头部通常由两部分组成:令牌的类型(即“JWT”)和正在使用的签名算法(如HMAC SHA256或RSA)。这是告诉接收方如何处理这个令牌的关键信息。头部是一个JSON对象,被编码为Base64Url字符串。
示例Header:
1 | { |
Payload(有效载荷)
有效载荷部分包含了实际要传输的数据。这里可以包含多个预定义的声明(claims)以及我们想要传输的任何其他数据。预定义的声明可能包括:iss(发行人)、exp(过期时间)、sub(主题)、aud(观众)等。与头部一样,有效载荷也是一个JSON对象,被编码为Base64Url字符串。
示例Payload:
1 | { |
Signature(签名)
为了创建签名部分,你必须使用由头部指定的算法(例如,HS256)对头部的Base64编码字符串和有效载荷的Base64编码字符串进行签名,使用一个密钥。签名的目的是保证JWT的头部和有效载荷没有被篡改,并验证发送方的身份。
签名算法示例:
1 | HMACSHA256( |
签名是将头部和有效载荷以Base64Url编码连接起来,然后用头部指定的算法和秘钥进行签名。结果也是一个Base64Url字符串。
将这三部分连接起来,就形成了一个完整的JWT。这个结构使得JWT自包含,拥有关于用户和其他元数据的所有必要信息,同时通过签名验证保证了数据的安全性。JWT的这种设计使其成为跨域认证和信息交换的理想选择。
实现基于JWT(JSON Web Tokens)的单点登录(SSO)方案,主要涉及到用户在一个系统中登录后,无需再次输入凭证即可访问其他系统的功能。这里将介绍一个基本的实现流程和JWT的存储方式。
JWT单点登录实现方案
1. 认证中心建立
- 设置一个认证中心,所有的登录请求都通过这个中心进行。
- 用户首次登录时,通过用户名和密码等凭证向认证中心发送请求。
2. 验证用户并生成JWT
- 认证中心验证用户的凭证。
- 凭证验证通过后,认证中心生成一个JWT,其中包含用户的身份信息和其他必要的声明(claims),然后将这个JWT返回给用户。
3. JWT的存储
- 客户端接收到JWT后,可以选择将其存储在Cookie、LocalStorage或SessionStorage中。每种方式都有其适用场景和安全性考虑。
4. 访问受保护的资源
- 用户在访问其他系统(服务提供者)的受保护资源时,需要在请求的Authorization头部附带JWT。
- 系统接收到请求后,从Authorization头部提取JWT,验证JWT的有效性。验证通过后,根据JWT中的信息提供相应的服务。
5. JWT的续签和失效处理
- JWT通常设有过期时间。系统需要合理设置过期时间,并提供JWT续签的机制。
- 用户访问时,如果JWT已经接近过期,系统可以自动续签一个新的JWT返回给用户。
JWT的存储方式
1. Cookie
- 将JWT存储在Cookie中是常见的做法,可以利用HttpOnly和Secure属性来增强安全性。
- Cookie跨域名不共享,但可以设置为对特定域名有效,适用于子域共享Token。
2. LocalStorage
- LocalStorage提供了更大的存储空间,易于前端JS脚本读取和管理。
- 但LocalStorage易受XSS攻击,需小心处理存储的数据。
3. SessionStorage
- SessionStorage的作用域限于当前会话,关闭浏览器标签页后数据消失,适用于敏感度较高的场景。
- 与LocalStorage相似,也易受XSS攻击。
安全考虑
- 在JWT中不应包含敏感数据,因为JWT是可解码的。
- 使用HTTPS传输JWT,避免中间人攻击。
- 考虑JWT的刷新策略和失效处理,防止过期的Token被滥用。
- 防范XSS和CSRF攻击,当JWT存储在Cookie中时,使用SameSite属性可以减少CSRF攻击的风险。
通过上述方案,可以实现一个基于JWT的单点登录系统,同时注意安全性和用户体验的平衡。
当用户登录时间较长或用户信息数据较大时,确实可能导致JWT的内容变大。这不仅会增加客户端和服务器之间传输数据的负担,还可能引起一些性能和安全问题。以下是几种处理策略:
1. 减少JWT负载
- 仅包含必要信息:确保JWT中只包含进行用户认证和授权所必需的信息,比如用户ID、用户名或角色等。敏感信息或不必要的信息不应包含在JWT中。
- 使用用户会话ID:而不是直接在JWT中存储大量用户信息,可以仅在JWT中存储一个会话ID或令牌ID。然后,应用服务器可以使用这个ID从数据库或内存中检索完整的用户信息。
2. 分割JWT
- 如果确实需要传输大量信息,可以考虑将JWT分割成多个较小的Token,每个Token负责不同的任务。例如,一个Token用于身份验证,另一个Token用于授权。
3. 使用JWT仅作为会话令牌
- JWT只用作会话令牌(Session Tokens),而具体的用户信息、权限等则存储在服务器端的会话存储中。这样,JWT本身保持轻量级,而用户相关的数据则由服务器管理。
4. 刷新Token
- 实现Token刷新机制。当用户活跃时,定期刷新JWT,同时在刷新过程中更新或减少JWT的负载。这样可以确保JWT中的信息是最新的,同时避免Token因过期而频繁重新登录。
5. 状态服务器
- 对于非常大型的应用,可以引入一个状态服务器(如OAuth2.0的授权服务器),专门负责管理用户的登录状态和会话信息。这样,JWT只需包含一个指向该状态服务器的引用标识符,由状态服务器处理具体的用户数据和权限检查。
安全性考虑
- 确保所有敏感操作(如Token刷新、用户信息的检索和更新)都通过安全的通道进行,最好是HTTPS,以防止中间人攻击。
- 对于存储在客户端的JWT和其他认证信息,要注意防范XSS攻击,避免存储过多敏感信息。
- 对于服务端,需要确保对用户信息的访问进行严格的权限控制,防止未授权访问。
通过上述策略,可以有效地管理JWT的大小,同时保持系统的性能和安全性。