在Spring+Kotlin中用gRPC拦截器校验ownerId并控制请求流转
gRPC ServerInterceptor 实现ownerId校验拦截
情况1:ownerId 来自请求头(Metadata)
如果ownerId通过请求头传递,可直接在interceptCall方法内完成校验:
class MyInterceptor : ServerInterceptor { // 按实际业务实现ownerId校验逻辑 private fun isValidOwnerId(ownerId: String?): Boolean { return ownerId != null && ownerId.isNotBlank() && ownerId.matches(Regex("^[0-9a-f]{24}$")) // 示例校验规则 } override fun <ReqT : Any?, RespT : Any?> interceptCall( call: ServerCall<ReqT, RespT>?, headers: Metadata?, next: ServerCallHandler<ReqT, RespT>? ): ServerCall.Listener<ReqT> { // 1. 从请求头提取ownerId val ownerId = headers?.get(Metadata.Key.of("owner-id", Metadata.ASCII_STRING_MARSHALLER)) // 2. 检查ownerId是否存在并有效 if (ownerId == null || !isValidOwnerId(ownerId)) { // 3. 无效则拦截请求,返回错误 call?.close( Status.INVALID_ARGUMENT.withDescription("ownerId不存在或无效"), Metadata() ) // 返回空Listener,终止后续调用链 return object : ServerCall.Listener<ReqT>() {} } // 4. 有效则放行请求 return next!!.startCall(call, headers) } }
情况2:ownerId 来自请求体
如果ownerId包含在请求消息体中,需要包装ServerCall.Listener,在接收消息时完成校验:
class MyInterceptor : ServerInterceptor { private fun isValidOwnerId(ownerId: String?): Boolean { return ownerId != null && ownerId.isNotBlank() && ownerId.matches(Regex("^[0-9a-f]{24}$")) } // 根据实际请求类型提取ownerId,可扩展支持多请求类型 private fun extractOwnerIdFromRequest(req: Any?): String? { return when (req) { is YourBizRequest -> req.ownerId // 其他请求类型的处理逻辑 else -> null } } override fun <ReqT : Any?, RespT : Any?> interceptCall( call: ServerCall<ReqT, RespT>?, headers: Metadata?, next: ServerCallHandler<ReqT, RespT>? ): ServerCall.Listener<ReqT> { val delegateListener = next!!.startCall(call, headers) return object : ServerCall.Listener<ReqT>() { override fun onMessage(message: ReqT) { val ownerId = extractOwnerIdFromRequest(message) if (ownerId == null || !isValidOwnerId(ownerId)) { call?.close( Status.INVALID_ARGUMENT.withDescription("ownerId不存在或无效"), Metadata() ) return } // 校验通过,传递消息到后续处理 delegateListener.onMessage(message) } // 转发其他Listener生命周期方法到委托实现 override fun onHalfClose() = delegateListener.onHalfClose() override fun onCancel() = delegateListener.onCancel() override fun onComplete() = delegateListener.onComplete() override fun onReady() = delegateListener.onReady() } } }
核心说明
isValidOwnerId需结合实际业务逻辑实现,比如数据库存活性校验、格式校验等- 拦截请求时通过
call.close()返回错误状态,客户端会收到对应的错误信息 - 请求体提取ownerId时,需确保覆盖所有需要校验的请求类型,或定义统一的请求接口规范
内容的提问来源于stack exchange,提问作者PudgeKim
相关产品推荐
相关产品推荐

