让Web过滤器链调用REST API做权限校验是否为不良实践?
微服务权限校验方案咨询
我正在实现微服务架构,包含Project、User、Product三个服务。用户可作为项目的所有者或参与者,当用户在Product服务执行操作时,需校验其对产品所属项目是否拥有权限。我设计了如下解决方案:创建一个WebFilter,通过调用Project服务的数据来校验用户对请求项目是否具备权限。
class ProjectAuthorizationFilter: WebFilter { companion object { const val PROJECT_HEADER = "X-Project-Id" } private lateinit var projectOperations: ProjectOperations override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> { return exchange.getPrincipal<UserDetails>() .flatMap { projectOperations.getPermittedProject(it.userId) } .filter { permittedProjects -> permittedProjects.any { it == exchange.request.headers.getOrDefault(PROJECT_HEADER, null) } } .switchIfEmpty(deniedAccess()) .flatMap { chain.filter(exchange) } } }
我想咨询该方案是否合理,即让Web过滤器链调用其他服务进行校验是否可行?
这个方案完全可行,但需要关注几个关键细节来保障稳定性与性能:
核心合理性
在Web过滤器中调用外部服务做跨服务权限校验是微服务架构的常规做法——Product服务本身不负责维护用户-项目的权限关系,依赖Project服务的数据源符合单一职责原则,能避免权限数据的冗余存储与不一致问题。
需要优化的关键问题
- 性能与可用性风险:每次请求都同步调用Project服务会拉高请求延迟,一旦Project服务故障,Product服务的所有请求都会被阻断。建议:
- 引入本地缓存(如Caffeine),缓存用户的项目权限列表,设置5-15分钟的过期时间,大幅减少跨服务调用次数
- 添加降级逻辑:当Project服务调用超时/失败时,临时返回权限拒绝或允许特定角色(如系统管理员)的请求
- 请求合法性校验缺失:代码未校验
X-Project-Id请求头是否存在,若请求头为空,getOrDefault返回null会导致权限校验逻辑直接失效。需先判断请求头是否存在,不存在则直接返回拒绝响应 - 异常处理不足:
projectOperations.getPermittedProject可能抛出远程调用异常(如连接失败、超时),当前代码未捕获这类异常,会导致请求报错而非返回标准的权限拒绝响应。需添加onErrorResume统一处理异常,返回拒绝结果 - 权限粒度扩展性:当前仅校验用户是否拥有项目权限,但不同操作(如创建/删除产品)可能需要区分所有者/参与者的权限级别。若后续有需求,可扩展逻辑:比如从请求方法/路径判断操作类型,或新增请求头携带权限要求
替代思路参考
如果Product服务请求量极大,可考虑通过事件同步权限数据到本地:Project服务更新用户权限时发送事件到消息队列,Product服务消费后更新本地缓存或数据库,彻底消除跨服务调用依赖,但会增加系统的复杂度。
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

