Android 拦截刷新令牌GRPC的调用

Android 拦截刷新令牌GRPC的调用,android,kotlin,interceptor,grpc,Android,Kotlin,Interceptor,Grpc,我在我的项目中使用GRPC和proto,我有密钥和授权令牌来访问服务器API。 所以,我需要使用我的权限更新密钥。 我正在建设这样一个频道: OkHttpChannelBuilder.forAddress(host, port) .usePlaintext() .intercept(auth, logger) .build() 我的拦截器看起来像: class AuthClientInterceptor( private val pref

我在我的项目中使用GRPC和proto,我有密钥和授权令牌来访问服务器API。 所以,我需要使用我的权限更新密钥。 我正在建设这样一个频道:

OkHttpChannelBuilder.forAddress(host, port)
        .usePlaintext()
        .intercept(auth, logger)
        .build()
我的拦截器看起来像:

class AuthClientInterceptor(
    private val prefs: Preferences,
    private val keyApi: KeyApi) : ClientInterceptor {

    companion object {
        private const val ACCESS_TOKEN = "authorization"
    }

    override fun <ReqT : Any?, RespT : Any?> interceptCall(method: MethodDescriptor<ReqT, RespT>?,
                                                       callOptions: CallOptions?,
                                                       next: Channel): ClientCall<ReqT, RespT> {

        val call = next.newCall(method, callOptions)

        val callForwarding = object : ClientInterceptors.CheckedForwardingClientCall<ReqT, RespT>(call) {
            override fun checkedStart(responseListener: Listener<RespT>?, headers: Metadata) {

            synchronized(this@AuthClientInterceptor) {
                val keyCreated = prefs.getAccessKeyCreated()
                val keyExpires = prefs.getAccessKeyExpires()
                val currentTime = System.currentTimeMillis()
                if (currentTime < keyCreated || currentTime > keyExpires) {
                    keyApi.issueNewKey(prefs.getAuthority())
                        .map { it.data }
                        .doOnSuccess { prefs.setAccessKey(it.token) }
                        .doOnSuccess { prefs.setAccessKeyCreated(it.createdDate) }
                        .doOnSuccess { prefs.setAccessKeyExpires(it.expiresDate) }
                        .blockingGet()
                }
            }

            val keyData = Metadata.Key.of(ACCESS_TOKEN, Metadata.ASCII_STRING_MARSHALLER)
                if (headers[keyData] == null) {
                    headers.put(keyData, "Bearer ${prefs.getAccessKey()}")
                }
                call.start(responseListener, headers)
            }
        }
        return callForwarding
    }
}
类AuthClientInterceptor( private val prefs:首选项, private val keyApi:keyApi):ClientInterceptor{ 伴星{ private const val ACCESS_TOKEN=“授权” } 重写调用(方法:MethodDescriptor?, callOptions:callOptions?, 下一个:频道):ClientCall{ val call=next.newCall(方法,callOptions) val callForwarding=object:ClientInterceptors.CheckedForwardingClientCall(调用){ 重写有趣的checkedStart(responseListener:Listener?,标题:元数据){ 同步的(this@AuthClientInterceptor) { val keyCreated=prefs.getAccessKeyCreated() val keyExpires=prefs.getAccessKeyExpires() val currentTime=System.currentTimeMillis() 如果(currentTimekeyExpires){ keyApi.issueNewKey(prefs.getAuthority()) .map{it.data} .doOnSuccess{prefs.setAccessKey(it.token)} .doOnSuccess{prefs.setAccessKeyCreated(it.createdDate)} .doOnSuccess{prefs.setAccessKeyExpires(it.expiresDate)} .blockingGet() } } val keyData=Metadata.Key.of(访问令牌,Metadata.ASCII\u字符串\u封送器) if(标题[keyData]==null){ headers.put(keyData,“Bearer${prefs.getAccessKey()}”) } call.start(responseListener、headers) } } 返回呼叫转移 } } 如您所见,我只是检查当前时间,并将其与创建的令牌和到期日期进行比较

所以,我不喜欢这样。我想实现这一点:

1) 向服务器发送请求

2) 检查响应。如果这意味着我的密钥过期,请同步刷新密钥并重复请求(如验证器)


但我没有找到解决方案,也没有找到任何关于使用gRPC实现此功能的有用信息。有人能帮我吗?

如果你想这样做,我想你必须按照你描述的那样在应用程序级别处理它。这是因为gRPC不知道您的应用程序级令牌

  • 制作RPC
  • 请注意,由于令牌过期,RPC失败
  • 调用刷新令牌的代码
  • 重复

  • 您所指的身份验证器是什么?

    以下是您可以使用的完整客户端侦听器类

    class Interceptor() : ClientInterceptor {
    
        override fun <ReqT : Any?, RespT : Any?> interceptCall(method: MethodDescriptor<ReqT, RespT>?, callOptions: CallOptions?, next: Channel?): ClientCall<ReqT, RespT> {
    
            return object : ClientCall<ReqT, RespT>() {
    
                var listener: Listener<RespT>? = null
                var metadata: Metadata? = null
                var message: ReqT? = null
                var request = 0
                var call: ClientCall<ReqT, RespT>? = null
    
                override fun start(responseListener: Listener<RespT>?, headers: Metadata?) {
                    this.listener = responseListener
                    this.metadata = headers
                }
    
                override fun sendMessage(message: ReqT) {
                    assert(this.message == null)
                    this.message = message
                }
    
                override fun request(numMessages: Int) {
                    request += numMessages
                    assert(this.message == null)
                }
    
                override fun isReady(): Boolean {
                    return false
                }
    
                override fun halfClose() {
    
                    startCall(object : ForwardingClientCallListener<RespT>() {
    
                        var delegate: Listener<RespT>? = null
    
                        override fun onReady() {
                            delegate = listener
                            super.onReady()
                        }
    
                        override fun delegate(): Listener<RespT> {
                            if (delegate == null) {
                                throw IllegalStateException()
                            }
                            return delegate!!
                        }
    
                        override fun onClose(status: Status?, trailers: Metadata?) {
                            if (delegate == null) {
                                super.onClose(status, trailers)
                                return
                            }
                            if (!needToRetry(status, trailers)) {
                                delegate = listener
                                super.onClose(status, trailers)
                                return
                            }
                            startCall(listener) // Only retry once
                        }
    
                        private fun needToRetry(status: Status?, trailers: Metadata?): Boolean {
                            if (status?.code?.toStatus() == UNAUTHENTICATED) {
                                Log.e("code", status?.code.toString())
                                return true
                            }
                            return false
                        }
                    })
                }
    
                private fun startCall(listener: Listener<RespT>?) {
                    call = next?.newCall(method, callOptions)
                    val headers = Metadata()
                    headers.merge(metadata)
                    call?.start(listener, headers)
                    assert(this.message != null)
                    call?.request(request)
                    call?.sendMessage(message)
                    call?.halfClose()
                }
    
                override fun cancel(message: String?, cause: Throwable?) {
                    if (call != null) {
                        call?.cancel(message, cause)
                    }
                    listener?.onClose(Status.CANCELLED.withDescription(message).withCause(cause), Metadata())
                }
            }
        }
    }
    
    class拦截器():ClientInterceptor{
    覆盖调用(方法:MethodDescriptor?,调用选项:callOptions?,下一步:通道?):ClientCall{
    返回对象:ClientCall(){
    变量侦听器:侦听器?=null
    变量元数据:元数据?=null
    var消息:需求?=null
    var请求=0
    变量调用:ClientCall?=null
    覆盖有趣的开始(responseListener:Listener?,headers:Metadata?){
    this.listener=responseListener
    this.metadata=headers
    }
    覆盖发送消息(消息:ReqT){
    断言(this.message==null)
    this.message=消息
    }
    覆盖乐趣请求(numMessages:Int){
    请求+=numMessages
    断言(this.message==null)
    }
    override fun isReady():布尔值{
    返回错误
    }
    覆盖半关闭(){
    startCall(对象:ForwardingClientCallListener(){
    变量委托:侦听器?=null
    重写onReady(){
    委托=侦听器
    super.onReady()
    }
    重写有趣的委托():侦听器{
    if(委托==null){
    抛出非法状态异常()
    }
    返回代理!!
    }
    覆盖关闭(状态:status?,拖车:Metadata?){
    if(委托==null){
    super.onClose(状态、拖车)
    返回
    }
    如果(!需要重试(状态,拖车)){
    委托=侦听器
    super.onClose(状态、拖车)
    返回
    }
    startCall(侦听器)//只重试一次
    }
    private fun needToRetry(状态:状态?、预告片:元数据?):布尔值{
    如果(状态?.code?.toStatus()==未经验证){
    Log.e(“代码”,状态?.code.toString())
    返回真值
    }
    返回错误
    }
    })
    }
    私人娱乐startCall(侦听器:侦听器?){
    call=next?.newCall(方法,callOptions)
    val headers=元数据()
    headers.merge(元数据)
    调用?.start(侦听器、标题)
    断言(this.message!=null)
    呼叫?请求(请求)
    呼叫?.sendMessage(消息)
    呼叫?.halfClose()
    }
    覆盖乐趣取消(消息:字符串?,原因:可丢弃?){
    如果(调用!=null){
    呼叫?.取消(消息、原因)
    }