面试题答案
一键面试JWT传递机制
- 生成JWT:在用户登录成功后,认证服务器根据用户信息(如用户名、用户ID、租户ID等)生成JWT。JWT包含头部(Header)、载荷(Payload)和签名(Signature)三部分。头部通常指定令牌的类型(如JWT)和使用的哈希算法(如HS256);载荷用于存放用户相关的声明(claims),例如用户标识、租户信息、权限信息等;签名则用于验证令牌的完整性和真实性。
- 传递方式:
- HTTP Headers:将JWT放在
Authorization
头部,格式为Bearer <token>
。例如,客户端在每次请求时,在请求头中添加Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
。这种方式简单且常用,适合大多数Web应用场景。 - Cookie:可以将JWT存储在Cookie中进行传递,但需要注意设置合适的安全属性,如
Secure
(确保仅在HTTPS连接下传输)和HttpOnly
(防止通过JavaScript访问,减少XSS攻击风险)。不过,由于跨域限制,Cookie传递JWT在跨域场景下可能需要额外的配置和处理。
- HTTP Headers:将JWT放在
与不同子系统及微服务的集成方式
- 网关层验证:在系统的API网关处进行JWT的验证。所有进入系统的请求首先经过网关,网关解析JWT,验证其签名的有效性、过期时间等。如果JWT无效,网关直接返回401未授权错误。这样可以在入口处统一拦截未授权的请求,减轻后端子系统和微服务的验证负担。
- 微服务内部验证:对于一些需要额外安全性保障的微服务,在微服务内部再次验证JWT。可以通过在微服务中引入JWT验证中间件来实现。当请求到达微服务时,中间件解析JWT并进行二次验证,确保请求的合法性。
- 共享密钥:为了验证JWT的签名,认证服务器和各个子系统、微服务需要共享相同的密钥。对于对称加密算法(如HS256),这个密钥用于签名和验证;对于非对称加密算法(如RS256),认证服务器使用私钥签名,子系统和微服务使用公钥验证。可以通过安全的配置中心来管理和分发密钥,确保密钥的安全性和一致性。
处理多租户之间权限隔离与共享的平衡问题
- 权限隔离:
- 租户特定权限声明:在JWT的载荷中包含租户特定的权限信息。例如,每个租户可能有不同的资源访问权限,在JWT中可以声明
tenantPermissions: ["view_tenant1_resource1", "edit_tenant1_resource2"]
。子系统和微服务在接收到JWT后,根据这些权限声明来判断用户是否有权限访问特定资源。 - 资源隔离:从数据层面确保不同租户的数据相互隔离。每个租户的数据可以存储在独立的数据库实例、数据库模式或表空间中。在进行数据库查询时,根据JWT中的租户ID添加相应的过滤条件,确保用户只能访问其所属租户的数据。
- 租户特定权限声明:在JWT的载荷中包含租户特定的权限信息。例如,每个租户可能有不同的资源访问权限,在JWT中可以声明
- 权限共享:
- 公共权限声明:对于一些所有租户都共享的权限,如系统公告查看权限,可以在JWT中设置公共权限声明,如
commonPermissions: ["view_system_notice"]
。子系统和微服务在验证权限时,不仅检查租户特定权限,也检查公共权限。 - 角色继承:可以设计一种角色继承机制,某些高级角色(如系统管理员)具有跨租户的管理权限。这些角色的权限在JWT中以特殊的声明表示,例如
role: "system_admin"
,并且系统在处理请求时,根据角色声明赋予其跨租户操作的权限。
- 公共权限声明:对于一些所有租户都共享的权限,如系统公告查看权限,可以在JWT中设置公共权限声明,如
- 动态权限管理:建立一个权限管理系统,允许管理员动态地为租户或用户分配权限。当权限发生变化时,认证服务器重新生成JWT并分发给用户。这样可以灵活地调整多租户之间的权限隔离与共享关系,适应业务的变化。