You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 06:52:26