我在项目中使用了带有原型的GRPC,并且我具有KEY和AUTHORITY令牌来访问服务器API。 因此,我需要使用我的AUTHORITY更新KEY。 我正在建立这样的频道:
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
}
}
如您所见,我只是检查当前时间,并将其与令牌创建和到期日期进行比较。
所以,我不喜欢那样。我想实现这个:
1)向服务器发送请求;
2)检查响应。如果这意味着我的密钥已过期,请同步刷新密钥并重复请求(如身份验证器)。
但是我没有找到解决方案或有关使用gRPC实现此功能的任何有用信息。有人可以帮我吗?
答案 0 :(得分:0)
如果您要这样做,我认为您必须按照您所描述的那样在应用程序级别进行处理。这是因为gRPC不了解您的应用程序级别令牌。
您指的是什么身份验证者?
答案 1 :(得分:0)
这是您可以使用的完整客户端拦截器类。
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())
}
}
}
}
它缓冲消息并重试,您可以在needToRetry(status, trailers)
有关更多信息,您可以访问此GitHub link.