多用户使用Google Cloud Speech异常,求Python服务端认证实现方案
解决多用户使用Google Cloud Speech API的认证冲突问题
首先得明确你遇到的核心问题:把服务账号密钥直接嵌入Android客户端并在本地缓存token,会导致多用户场景下的token并发冲突——所有客户端共享同一个服务账号的token配额,且本地缓存的token在多设备刷新时会互相干扰,同时直接在客户端暴露服务账号密钥是严重的安全风险,这也是官方要求将认证逻辑委托到服务端的核心原因。
下面是具体的实现方案,我们用Python搭建一个后端服务,统一处理Speech API的认证和请求,Android客户端只需要把音频数据发送到后端即可:
第一步:Python后端实现
1. 安装依赖
先安装需要的Python包:
pip install flask google-cloud-speech python-dotenv
2. 编写后端代码
创建一个app.py文件,实现接收音频并调用Speech API的接口:
from flask import Flask, request, jsonify from google.cloud import speech_v1p1beta1 as speech import os from dotenv import load_dotenv # 加载环境变量(建议把服务账号密钥路径放在.env文件里,不要硬编码) load_dotenv() os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = os.getenv("GOOGLE_SERVICE_ACCOUNT_KEY_PATH") app = Flask(__name__) client = speech.SpeechClient() @app.route('/recognize-speech', methods=['POST']) def recognize_speech(): # 接收客户端上传的音频文件 if 'audio' not in request.files: return jsonify({'error': 'No audio file provided'}), 400 audio_file = request.files['audio'] audio_content = audio_file.read() # 配置Speech API请求参数 audio = speech.RecognitionAudio(content=audio_content) config = speech.RecognitionConfig( encoding=speech.RecognitionConfig.AudioEncoding.LINEAR16, sample_rate_hertz=16000, language_code='zh-CN', # 根据你的需求修改语言代码 enable_automatic_punctuation=True ) # 调用Speech API try: response = client.recognize(config=config, audio=audio) # 提取识别结果 results = [] for result in response.results: results.append({ 'transcript': result.alternatives[0].transcript, 'confidence': result.alternatives[0].confidence }) return jsonify({'results': results}), 200 except Exception as e: return jsonify({'error': str(e)}), 500 if __name__ == '__main__': # 生产环境建议用Gunicorn等WSGI服务器,不要用Flask自带的服务器 app.run(host='0.0.0.0', port=5000, debug=False)
3. 配置服务账号
- 把你的服务账号密钥文件(
credential.json)放在服务器的安全目录下 - 创建
.env文件,添加:GOOGLE_SERVICE_ACCOUNT_KEY_PATH=/path/to/your/credential.json
第二步:修改Android客户端代码
移除本地的AccessTokenTask相关逻辑,改为通过HTTP请求把音频数据发送到后端:
// 示例:用OkHttp发送音频文件到后端 private void sendAudioToBackend(byte[] audioData) { OkHttpClient client = new OkHttpClient(); RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("audio", "recording.wav", RequestBody.create(audioData, MediaType.parse("audio/wav"))) .build(); Request request = new Request.Builder() .url("http://your-server-ip:5000/recognize-speech") // 替换成你的后端地址 .post(requestBody) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "Failed to send audio to backend", e); // 处理失败逻辑 } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { String responseBody = response.body().string(); // 解析后端返回的JSON结果 // 示例:用Gson解析 RecognitionResult result = new Gson().fromJson(responseBody, RecognitionResult.class); // 处理识别结果 } else { Log.e(TAG, "Backend returned error: " + response.code()); } } }); } // 辅助类用于解析JSON结果 static class RecognitionResult { List<SpeechResult> results; static class SpeechResult { String transcript; float confidence; } }
为什么这个方案能解决问题?
- 避免认证冲突:后端统一管理服务账号的认证和token刷新,所有客户端共享后端的认证会话,不会出现多设备token互相干扰的情况
- 提升安全性:服务账号密钥只存储在服务器端,不会暴露给Android客户端,防止密钥泄露导致的权限滥用
- 便于配额管理:后端可以统一控制API调用的频率和配额,避免单个客户端过度消耗资源
内容的提问来源于stack exchange,提问作者Backkom
相关产品推荐
相关产品推荐

