错误:OAuth2Credentials 实例不支持刷新访问令牌。如何使用令牌值字符串创建 AccessToken 实例?

问题描述 投票:0回答:2

我正在使用 Android 上的 Google Speech to Text 服务将语音流式传输到文本。 这里是官方示例库。 示例运行成功。但是或者,您应该在服务器端获取访问令牌,并将其提供给客户端应用程序。

所以我设置了一个服务器并为应用程序创建 RESTful api 以获取访问令牌。

{"token":"1234567890sdertyuikjhgfghjk....."}

还可以使用 api:https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={token} 获取令牌信息:

{
 "issued_to": "102073270616313859663",
 "audience": "102073270616313859663",
 "scope": "https://www.googleapis.com/auth/cloud-platform",
 "expires_in": 3600,
 "access_type": "offline"
}

然后创建一个AccessToken实例:

AccessToken token = new AccessToken(tokenValue, expiresIn);

但是出现以下错误:

07-04 20:14:07.395 3023-3067/com.google.cloud.android.speech E/SpeechService: Error calling the API.
io.grpc.StatusRuntimeException: UNKNOWN
    at io.grpc.Status.asRuntimeException(Status.java:543)
    at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:395)
    at io.grpc.ClientInterceptors$CheckedForwardingClientCall.start(ClientInterceptors.java:202)
    at io.grpc.stub.ClientCalls.startCall(ClientCalls.java:276)
    at io.grpc.stub.ClientCalls.asyncStreamingRequestCall(ClientCalls.java:266)
    at io.grpc.stub.ClientCalls.asyncBidiStreamingCall(ClientCalls.java:106)
    at com.google.cloud.speech.v1.SpeechGrpc$SpeechStub.streamingRecognize(SpeechGrpc.java:217)
    at com.google.cloud.android.speech.SpeechService.startRecognizing(SpeechService.java:264)
    at com.google.cloud.android.speech.MainActivity$1.onVoiceStart(MainActivity.java:62)
    at com.google.cloud.android.speech.VoiceRecorder$ProcessVoice.run(VoiceRecorder.java:199)
    at java.lang.Thread.run(Thread.java:764)
 Caused by: java.lang.IllegalStateException: OAuth2Credentials instance does not support refreshing the access token. An instance with a new access token should be used, or a derived type that supports refreshing.
    at com.google.auth.oauth2.OAuth2Credentials.refreshAccessToken(OAuth2Credentials.java:208)
    at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:175)
    at com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:161)
    at com.google.cloud.android.speech.SpeechService$GoogleCredentialsInterceptor.getRequestMetadata(SpeechService.java:532)
    at com.google.cloud.android.speech.SpeechService$GoogleCredentialsInterceptor.access$900(SpeechService.java:450)
    at com.google.cloud.android.speech.SpeechService$GoogleCredentialsInterceptor$1.checkedStart(SpeechService.java:474)
    at io.grpc.ClientInterceptors$CheckedForwardingClientCall.start(ClientInterceptors.java:194)
    at io.grpc.stub.ClientCalls.startCall(ClientCalls.java:276) 
    at io.grpc.stub.ClientCalls.asyncStreamingRequestCall(ClientCalls.java:266) 
    at io.grpc.stub.ClientCalls.asyncBidiStreamingCall(ClientCalls.java:106) 
    at com.google.cloud.speech.v1.SpeechGrpc$SpeechStub.streamingRecognize(SpeechGrpc.java:217) 
    at com.google.cloud.android.speech.SpeechService.startRecognizing(SpeechService.java:264) 
    at com.google.cloud.android.speech.MainActivity$1.onVoiceStart(MainActivity.java:62) 
    at com.google.cloud.android.speech.VoiceRecorder$ProcessVoice.run(VoiceRecorder.java:199) 
    at java.lang.Thread.run(Thread.java:764) 

我可以使用示例代码:

 final InputStream stream = getResources().openRawResource(R.raw.credential);
 final GoogleCredentials credentials = 
 GoogleCredentials.fromStream(stream).createScoped(SCOPE);
 final AccessToken token = credentials.refreshAccessToken();

并获得一个working Token,并使用

getTokenValue()
获取其token值,并通过
getExpirationTime
获取其到期时间。然后创建一个 Token 实例:
AccessToken token = new AccessToken(tokenValue, expiresIn);
返回一个 AccessToken 实例。但它会导致同样的错误。

所以我的问题是当我获得令牌值字符串和到期时间时如何创建一个workingAccessToken实例。

android google-cloud-platform google-authentication google-speech-api
2个回答
0
投票

不幸的是,我仍然无法通过构造函数创建一个有效的

AccessToken
。但是我使用套接字服务器来解决问题。因为
AccessToken
已经实现了
Serializable
接口。所以在客户端和服务器之间进行通信要容易得多。

服务器

private void  runServer() throws IOException, ClassNotFoundException{
    ServerSocket ss = new ServerSocket(port);

    Socket socket = ss.accept();
    ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream());
    ObjectInputStream is = new ObjectInputStream(socket.getInputStream());

    final InputStream stream = new ByteArrayInputStream(credential.getBytes(StandardCharsets.UTF_8));
    final GoogleCredentials credentials = GoogleCredentials.fromStream(stream)
                    .createScoped(SCOPE);
    final AccessToken token = credentials.refreshAccessToken();
    os.writeObject(token);
}

0
投票

我遇到过类似的问题,以下解决方案对我有用:

String accessToken = "xxxx"; // Replace this with your access token
long timestampWhenTokenGeneratedInSecond = 1678956050; // Replace this with the timestamp when access token was generated
long tokenExpiresInSecond = 3599; // Replace this with your access token expiration time
long expirationTimeInMS = (timestampWhenTokenGeneratedInSecond + tokenExpiresInSecond) * 1000; // Convert it to milliseconds
Credentials credentials = GoogleCredentials.create(new AccessToken(accessToken, new Date(expirationTimeInMS)));

AccessToken
构造函数中,您需要传递一个
java.util.Date
的对象,并带有以毫秒为单位的令牌过期时间戳。


备选方案(如果您不知道/有到期时间):您可以使用

new AccessToken(token, null)
.

© www.soinside.com 2019 - 2024. All rights reserved.