移动端应用如何安全访问智能语音交互服务

为了避免在移动端App或者桌面端工具中保存固定AccessKey ID和AccessKey Secret可能引起的泄露风险,您可以通过在App服务端创建Token并下发到移动端使用,或使用STS临时访问凭证调用语音服务两种方式,更加安全地访问智能语音交互服务。

背景信息

方案

适用接口

方案一:通过App服务端创建Token并下发到移动端使用

  • 一句话识别

  • 实时语音识别

  • 录音文件识别极速版

  • 语音合成

  • 实长文本时语音合成

  • 语音分析等

方案二:使用STS临时访问凭证调用语音服务

离线语音合成

方案一:通过App服务端创建Token并下发到移动端使用

前提条件

已开通智能语音交互服务,并根据产品文档调试成功,具体操作,请参见开通服务

适用场景

如果您作为移动App开发者或者桌面端开发者,希望您的用户调用阿里云智能语音交互产品的语音合成、一句话识别、实时识别等服务时,为避免在移动端App或者桌面端工具中保存固定AccessKey ID和AccessKey Secret可能引起的泄露风险,您可以使用App服务端下发语音Token调用服务。

交互流程

image
  1. App端向用户应用服务器请求一个调用智能语音交互接口所依赖的语音Token,此处使用您自有的通信协议即可,比如用户登录时自动请求或服务端自动下发,或定时向应用服务器发起请求。

  2. 用户应用服务器向阿里云智能语音服务发起创建语音Token的真正请求,此处请您使用阿里云SDK或智能语音交互SDK来创建Token,创建Token所需的AccessKey ID和AccessKey Secret保存在您的应用服务器上。由于语音Token具有时效性,您可以在有效期范围内直接返回给App端,无需每次都向智能语音交互服务请求新的Token。

  3. 智能语音交互服务返回给应用服务器一个语音Token信息,包括Token字符串及有效期时间,在有效期内,您可以多次复用该Token而无需重新创建,Token的使用不受不同用户、不同设备的限制。

  4. 用户应用服务器将Token返回给App端,此时App端可以缓存并使用该Token,直到Token失效。当Token失效时,App端需要向应用服务器申请新的Token。假设Token凭证有效期为24小时,App端可以在Token过期前1到2小时主动向应用服务器请求更新Token。

  5. App端使用获取到的Token构建请求,向阿里云智能语音交互公共云发起调用,比如调用实时语音识别、一句话识别、语音合成等接口(不包括录音文件识别、录音文件识别闲时版等离线类接口),更多信息,请参见阿里云智能语音交互相关文档。

此方案无需过多额外设置或开发,将AccessKey ID和AccessKey Secret保存到移动端改为保存到用户自己的服务端,并通过服务端创建语音Token再下发给移动端使用,兼容了使用安全性及开发便捷性。

方案二:使用STS临时访问凭证调用语音服务

阿里云STS(Security Token Service)是阿里云提供的一种临时访问权限管理服务。您可以通过STS服务给其他用户颁发临时访问凭证,该用户可使用临时访问凭证,在规定时间内调用智能语音交互的录音文件识别服务(含闲时版)。临时访问凭证无需透露您的长期密钥,保障您的账户更加安全。

前提条件

已确保当前账号为阿里云账号或者被授予AliyunRAMFullAccess权限的RAM用户。关于为RAM用户授权的具体步骤,请参见为RAM用户授权

适用场景

如果您作为移动App开发者或者桌面端开发者,希望您的用户调用阿里云智能语音交互产品的录音文件识别等服务时,避免在移动端App或者桌面端工具中保存固定AccessKey ID和AccessKey Secret可能引起的泄露风险,您可以使用STS授权用户调用服务。

交互流程

image
  1. App端向用户应用服务器请求STS临时访问凭证,此处使用用户自有的通信协议即可,比如用户登录时自动请求或服务端自动下发,或定时向应用服务器发起请求。

  2. 用户应用服务器向阿里云STS服务发起STS请求,此处请使用阿里云SDK,根据应用服务器自身保存的固定AK向STS请求生成一个临时凭证。

  3. STS返回给应用服务器一个临时访问凭证,包括临时访问密钥(AccessKey ID和AccessKey Secret)、安全令牌(SecurityToken)、该凭证的过期时间等信息。

  4. 用户应用服务器将临时凭证返回给App端,此时App端可以缓存并使用该凭证,直到凭证失效。当凭证失效时,App端需要向应用服务器申请新的临时访问凭证。假设临时访问凭证有效期为1小时,App端可以每30分钟或者每50分钟的频率向应用服务器请求更新临时访问凭证。

  5. App端使用获取到的临时凭证构建请求,向阿里云智能语音交互公共云发起调用,更多信息,请参见阿里云智能语音交互相关开发文档。

    本文以录音文件识别为例,为您介绍相关示例代码。

操作步骤

步骤一:创建RAM用户

  1. 登录RAM控制台

  2. 在左侧导航栏,选择身份管理 > 用户

  3. 单击创建用户

  4. 输入登录名称显示名称

  5. 访问方式区域下,选择使用永久AccessKey访问,然后单击确定image

  6. 单击复制,保存访问密钥(AccessKey ID 和 AccessKey Secret)。

步骤二:为RAM用户授予请求AssumeRole的权限

  1. 在已创建的RAM用户右侧,单击对应的添加权限

  2. 在添加权限页面,选择AliyunSTSAssumeRoleAccess系统策略。image

  3. 单击确定

步骤三:创建用于获取临时访问凭证的角色

  1. 在左侧导航栏,选择身份管理 > 角色

  2. 单击创建角色,可信实体类型选择阿里云账号,单击下一步

  3. 填写角色名称(此处以stsrole为例),选择当前云账号image

  4. 单击完成。完成角色创建后,单击关闭

  5. 在RAM角色管理页面,搜索框输入角色名称stsrole。

  6. 单击复制,保存角色的ARN。image

步骤四:为角色授予调用录音文件识别接口的权限

  1. 创建上传文件的自定义权限策略。

    1. 在左侧导航栏,选择权限管理 > 权限策略

    2. 单击创建权限策略

    3. 创建权限策略页面,单击脚本编辑

      如果您需要角色具备调用录音文件识别、录音文件识别闲时版服务,请参考以下配置示例。

      重要

      以下示例仅供参考。您需要根据实际需求配置更细粒度的授权策略,防止出现权限过大的风险。关于更细粒度的授权策略配置详情,请参见通过RAM或STS服务向其他用户授权

      {
          "Version": "1",
          "Statement": [
              {
                  "Action": "nls:SubmitTask",
                  "Resource": "*",
                  "Effect": "Allow"
              },
              {
                  "Action": "nls:GetTaskResult",
                  "Resource": "*",
                  "Effect": "Allow"
              }
          ]
      }
    4. 策略配置完成后,单击继续编辑基本信息

    5. 基本信息区域,填写策略名称(此处以nls-stsuser-policy为例),然后单击确定image

  2. 为上面创建的RAM角色stsrole授予自定义权限策略。

    1. 在左侧导航栏,选择身份管理 > 角色

    2. 角色页面,找到目标RAM角色stsrole。

    3. 单击RAM角色stsrole右侧的添加权限

    4. 添加权限页面下的自定义策略页签,选择已创建的自定义权限策略nls-stsuser-policy。

    5. 单击确定image

步骤五:服务端获取STS临时访问凭证

需要注意,此步骤并不是在客户端侧(移动端App或桌面端)调用的,您可以在自己的应用服务器侧,通过您持有的固定AccessKey ID和AccessKey Secret(即步骤一创建RAM用户时保存的账户信息)创建STS临时访问凭证,然后将该凭证通过您已有的交互链路返回给客户端侧。客户端侧获取到临时访问凭证后,再调用步骤六中的录音文件识别服务。

  • 方式一:使用阿里云SDK(推荐)

    您可以使用多语言STS SDK获取临时访问凭证。

    以下Java代码用于获取临时访问凭证。

    引入POM依赖:

       <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-java-sdk-core</artifactId>
                <version>4.5.6</version>
            </dependency>
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-java-sdk-sts</artifactId>
                <version>3.0.0</version>
            </dependency>

    完整示例代码如下:

    import com.aliyuncs.CommonRequest;
    import com.aliyuncs.CommonResponse;
    import com.aliyuncs.DefaultAcsClient;
    import com.aliyuncs.IAcsClient;
    import com.aliyuncs.auth.sts.AssumeRoleRequest;
    import com.aliyuncs.auth.sts.AssumeRoleResponse;
    import com.aliyuncs.exceptions.ClientException;
    import com.aliyuncs.http.MethodType;
    import com.aliyuncs.http.ProtocolType;
    import com.aliyuncs.profile.DefaultProfile;
    import com.aliyuncs.profile.IClientProfile;
    
    public class CreateStsCredentialsDemo {
    
        public static void main(String args[]) throws ClientException {
            //同region STS的OpenAPI地址
            String endpoint = "sts.aliyuncs.com";
    
            // 填写步骤一生成的访问密钥AccessKey ID和AccessKey Secret。
            String accessKeyId = "******";
            String accessKeySecret = "******";
    
            // 填写步骤三获取的角色ARN, 一般是: acs:ram::********:role/***
            String roleArn = "******";
    
            // 自定义角色会话名称,用来区分不同的令牌,例如可填写为nls-role-session-99。
            String roleSession = "nls-role-session-99";
    
            // 添加endpoint(直接使用STS endpoint,前两个参数留空,无需添加region ID)
            DefaultProfile.addEndpoint("", "Sts", endpoint);
            // 构造default profile(参数留空,无需添加region ID)
            IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
            // 用profile构造client
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSession);
            final AssumeRoleResponse response = client.getAcsResponse(request);
    
            String stsAccessKeyId = response.getCredentials().getAccessKeyId();
            String stsAccessKeySecret = response.getCredentials().getAccessKeySecret();
            String stsToken = response.getCredentials().getSecurityToken();
    
            System.out.println("Expiration: " + response.getCredentials().getExpiration());
            System.out.println("Access Key Id: " + stsAccessKeyId);
            System.out.println("Access Key Secret: " + stsAccessKeySecret);
            System.out.println("Security Token: " + stsToken);
            System.out.println("RequestId: " + response.getRequestId());
        }
    }

  • 方式二:使用REST API

    您可以通过调用STS服务接口AssumeRole获取临时访问凭证。

步骤六:客户端使用临时访问凭证调用录音文件识别服务(或录音文件识别闲时版)

如果您使用的是录音文件识别闲时版服务,本文流程及以下示例代码都可复用。

为了调用录音文件识别闲时版服务,下方的示例代码的产品信息需要从:

PRODUCT = "nls-filetrans"
DOMAIN = "filetrans.cn-shanghai.aliyuncs.com"
API_VERSION = "2018-08-17"

改为:

PRODUCT = "SpeechFileTranscriberLite"
DOMAIN = "speechfiletranscriberlite.cn-shanghai.aliyuncs.com"
API_VERSION = "2021-12-21"

Java代码演示通过STS临时访问凭证调用录音文件识别服务

引入POM依赖:

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.5.6</version>
        </dependency>

以下是Java代码演示通过STS临时访问凭证调用录音文件转写服务的完整示例:

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;

public class FileTransByStsJavaDemo {
    // 地域ID,常量,固定值。
    public static final String REGIONID = "cn-shanghai";
    public static final String ENDPOINTNAME = "cn-shanghai";
    public static final String PRODUCT = "nls-filetrans";
    public static final String DOMAIN = "filetrans.cn-shanghai.aliyuncs.com";
    public static final String API_VERSION = "2018-08-17";
    public static final String POST_REQUEST_ACTION = "SubmitTask";
    public static final String GET_REQUEST_ACTION = "GetTaskResult";
    // 请求参数
    public static final String KEY_APP_KEY = "appkey";
    public static final String KEY_FILE_LINK = "file_link";
    public static final String KEY_VERSION = "version";
    public static final String KEY_ENABLE_WORDS = "enable_words";
    // 响应参数
    public static final String KEY_TASK = "Task";
    public static final String KEY_TASK_ID = "TaskId";
    public static final String KEY_STATUS_TEXT = "StatusText";
    public static final String KEY_RESULT = "Result";
    // 状态值
    public static final String STATUS_SUCCESS = "SUCCESS";
    private static final String STATUS_RUNNING = "RUNNING";
    private static final String STATUS_QUEUEING = "QUEUEING";
    // 阿里云鉴权client
    IAcsClient client;
    public FileTransByStsJavaDemo(String stsAccessKeyId, String stsAccessKeySecret, String stsToken) {
        // 设置endpoint
        try {
            DefaultProfile.addEndpoint(ENDPOINTNAME, REGIONID, PRODUCT, DOMAIN);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        // 创建DefaultAcsClient实例并初始化
        DefaultProfile profile = DefaultProfile.getProfile(REGIONID, stsAccessKeyId, stsAccessKeySecret, stsToken);
        this.client = new DefaultAcsClient(profile);
    }
    public String submitFileTransRequest(String appKey, String fileLink) {
        /**
         * 1. 创建CommonRequest,设置请求参数。
         */
        CommonRequest postRequest = new CommonRequest();
        // 设置域名
        postRequest.setDomain(DOMAIN);
        // 设置API的版本号,格式为YYYY-MM-DD。
        postRequest.setVersion(API_VERSION);
        // 设置action
        postRequest.setAction(POST_REQUEST_ACTION);
        // 设置产品名称
        postRequest.setProduct(PRODUCT);
        /**
         * 2. 设置录音文件识别请求参数,以JSON字符串的格式设置到请求Body中。
         */
        JSONObject taskObject = new JSONObject();
        // 设置appkey
        taskObject.put(KEY_APP_KEY, appKey);
        // 设置音频文件访问链接
        taskObject.put(KEY_FILE_LINK, fileLink);
        // 新接入请使用4.0版本,已接入(默认2.0)如需维持现状,请注释掉该参数设置。
        taskObject.put(KEY_VERSION, "4.0");
        // 设置是否输出词信息,默认为false,开启时需要设置version为4.0及以上。
        taskObject.put(KEY_ENABLE_WORDS, true);
        String task = taskObject.toJSONString();
        System.out.println(task);
        // 设置以上JSON字符串为Body参数。
        postRequest.putBodyParameter(KEY_TASK, task);
        // 设置为POST方式的请求。
        postRequest.setMethod(MethodType.POST);
        /**
         * 3. 提交录音文件识别请求,获取录音文件识别请求任务的ID,以供识别结果查询使用。
         */
        String taskId = null;
        try {
            CommonResponse postResponse = client.getCommonResponse(postRequest);
            System.err.println("提交录音文件识别请求的响应:" + postResponse.getData());
            if (postResponse.getHttpStatus() == 200) {
                JSONObject result = JSONObject.parseObject(postResponse.getData());
                String statusText = result.getString(KEY_STATUS_TEXT);
                if (STATUS_SUCCESS.equals(statusText)) {
                    taskId = result.getString(KEY_TASK_ID);
                }
            }
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return taskId;
    }
    public String getFileTransResult(String taskId) {
        /**
         * 1. 创建CommonRequest,设置任务ID。
         */
        CommonRequest getRequest = new CommonRequest();
        // 设置域名
        getRequest.setDomain(DOMAIN);
        // 设置API版本
        getRequest.setVersion(API_VERSION);
        // 设置action
        getRequest.setAction(GET_REQUEST_ACTION);
        // 设置产品名称
        getRequest.setProduct(PRODUCT);
        // 设置任务ID为查询参数
        getRequest.putQueryParameter(KEY_TASK_ID, taskId);
        // 设置为GET方式的请求
        getRequest.setMethod(MethodType.GET);
        /**
         * 2. 提交录音文件识别结果查询请求
         * 以轮询的方式进行识别结果的查询,直到服务端返回的状态描述为“SUCCESS”或错误描述,则结束轮询。
         */
        String result = null;
        while (true) {
            try {
                CommonResponse getResponse = client.getCommonResponse(getRequest);
                System.err.println("识别查询结果:" + getResponse.getData());
                if (getResponse.getHttpStatus() != 200) {
                    break;
                }
                JSONObject rootObj = JSONObject.parseObject(getResponse.getData());
                String statusText = rootObj.getString(KEY_STATUS_TEXT);
                if (STATUS_RUNNING.equals(statusText) || STATUS_QUEUEING.equals(statusText)) {
                    // 继续轮询,注意设置轮询时间间隔。
                    Thread.sleep(10000);
                }
                else {
                    // 状态信息为成功,返回识别结果;状态信息为异常,返回空。
                    if (STATUS_SUCCESS.equals(statusText)) {
                        result = rootObj.getString(KEY_RESULT);
                        // 状态信息为成功,但没有识别结果,则可能是由于文件里全是静音、噪音等导致识别为空。
                        if(result == null) {
                            result = "";
                        }
                    }
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }
    public static void main(String args[]) throws Exception {
        // 相比非STS模式,此时此处填写之前生成的STS临时访问凭证。
        // 特别需要注意的是:临时访问凭证存在有效期,在有效期内您可以一直使用,但是请在过期前及时再次获取
        final String stsAccessKeyId = "STS.******";
        final String stsAccessKeySecret = "******";
        final String stsToken = "******";
        final String appKey = "******";
        
        String fileLink = "https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav";
        FileTransByStsJavaDemo demo = new FileTransByStsJavaDemo(stsAccessKeyId, stsAccessKeySecret, stsToken);
        // 第一步:提交录音文件识别请求,获取任务ID用于后续的识别结果轮询。
        String taskId = demo.submitFileTransRequest(appKey, fileLink);
        if (taskId != null) {
            System.out.println("录音文件识别请求成功,task_id: " + taskId);
        }
        else {
            System.out.println("录音文件识别请求失败!");
            return;
        }
        // 第二步:根据任务ID轮询识别结果。
        String result = demo.getFileTransResult(taskId);
        if (result != null) {
            System.out.println("录音文件识别结果查询成功:" + result);
        }
        else {
            System.out.println("录音文件识别结果查询失败!");
        }
    }
}

Python代码演示通过STS临时访问凭证调用录音文件识别服务

# -*- coding: utf-8 -*-
import json
import time
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.auth.credentials import StsTokenCredential
from aliyunsdkcore.request import CommonRequest

REGION_ID = "cn-shanghai"
DOMAIN = "filetrans.cn-shanghai.aliyuncs.com"
PRODUCT = "nls-filetrans"
API_VERSION = "2018-08-17"
POST_REQUEST_ACTION = "SubmitTask"
GET_REQUEST_ACTION = "GetTaskResult"
KEY_APP_KEY = "appkey"
KEY_FILE_LINK = "file_link"
KEY_VERSION = "version"
KEY_TASK = "Task"
KEY_TASK_ID = "TaskId"
KEY_STATUS_TEXT = "StatusText"

def submitTask(stsAkId, stsAkSecret, stsToken, appKey, fileLink):
    # 创建AcsClient实例
    stsTokenCredential = StsTokenCredential(stsAkId, stsAkSecret, stsToken)
    client = AcsClient(region_id=REGION_ID, credential=stsTokenCredential)
    # 创建提交录音文件识别请求,并设置请求参数。
    postRequest = CommonRequest()
    postRequest.set_domain(DOMAIN)
    postRequest.set_version(API_VERSION)
    postRequest.set_product(PRODUCT)
    postRequest.set_action_name(POST_REQUEST_ACTION)
    postRequest.set_method('POST')

    task = {KEY_APP_KEY : appKey, KEY_FILE_LINK : fileLink, KEY_VERSION : "4.0", "enable_words" : False}
    task = json.dumps(task)
    print(task)
    postRequest.add_body_params(KEY_TASK, task)
    taskId = ""
    try :
        # 提交录音文件识别请求,处理服务端返回的响应。
        postResponse = client.do_action_with_exception(postRequest)
        postResponse = json.loads(postResponse)
        print(postResponse)
        # 获取录音文件识别请求任务的ID,以供识别结果查询使用。
        statusText = postResponse[KEY_STATUS_TEXT]
        if statusText == "SUCCESS" :
            print("录音文件识别请求成功响应!")
            taskId = postResponse[KEY_TASK_ID]
            print("taskId = " + taskId)
        else :
            print("录音文件识别请求失败!")
    except ServerException as e:
        print(e)
    except ClientException as e:
        print(e)

    print(taskId)
    return taskId

def queryResult(stsAkId, stsAkSecret, stsToken, taskId):
    # 创建CommonRequest,设置任务ID。
    stsTokenCredential = StsTokenCredential(stsAkId, stsAkSecret, stsToken)
    client = AcsClient(region_id=REGION_ID, credential=stsTokenCredential)

    getRequest = CommonRequest()
    getRequest.set_domain(DOMAIN)
    getRequest.set_version(API_VERSION)
    getRequest.set_product(PRODUCT)
    getRequest.set_action_name(GET_REQUEST_ACTION)
    getRequest.set_method('GET')
    getRequest.add_query_param(KEY_TASK_ID, taskId)

    # 提交录音文件识别结果查询请求
    # 以轮询的方式进行识别结果的查询,直到服务端返回的状态描述符为"SUCCESS"、"SUCCESS_WITH_NO_VALID_FRAGMENT",或者为错误描述,则结束轮询。
    statusText = ""
    while True :
        try :
            getResponse = client.do_action_with_exception(getRequest)
            getResponse = json.loads(getResponse)
            print (json.dumps(getResponse).decode('unicode-escape'))
            statusText = getResponse[KEY_STATUS_TEXT]
            if statusText == "RUNNING" or statusText == "QUEUEING" :
                # 继续轮询
                time.sleep(5)
            else :
                # 退出轮询
                break
        except ServerException as e:
            print (e)
        except ClientException as e:
            print (e)
    if statusText == "SUCCESS" :
        print ("录音文件识别成功!")
    else :
        print ("录音文件识别失败!")

# 智能语音交互Appkey,获取Appkey请前往控制台:https://nls-portal.console.aliyun.com/applist
appKey = '******'
# 测试录音的url
fileLink = "https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav"

# 相比非STS模式,此时此处填写之前生成的STS临时访问凭证(含STS账号信息及SecurityToken)
# 特别需要注意的是:临时访问凭证存在有效期,在有效期内您可以一直使用,但是请在过期前及时再次获取
stsAkId = 'STS.******'
stsAkSecret = '******'
stsToken = '************'
print("--- submit one file ---")
taskId = submitTask(stsAkId, stsAkSecret, stsToken, appKey, fileLink)

print("--- query result ---")
queryResult(stsAkId, stsAkSecret, stsToken, taskId)

Go代码演示通过STS临时访问凭证调用录音文件转写服务

关于阿里云SDK Go语言版本的安装操作,请参见Go SDK 依赖STS SDK

以下是Go代码演示通过STS临时访问凭证调用录音文件转写服务的完整示例:

package main

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
)

func main() {
	// 地域ID,固定值。
	const REGION_ID string = "cn-shanghai"
	const ENDPOINT_NAME string = "cn-shanghai"
	const PRODUCT string = "nls-filetrans"
	const DOMAIN string = "filetrans.cn-shanghai.aliyuncs.com"
	const API_VERSION string = "2018-08-17"
	const POST_REQUEST_ACTION string = "SubmitTask"
	const GET_REQUEST_ACTION string = "GetTaskResult"
	// 请求参数
	const KEY_APP_KEY string = "appkey"
	const KEY_FILE_LINK string = "file_link"
	const KEY_VERSION string = "version"
	const KEY_ENABLE_WORDS string = "enable_words"
	// 响应参数
	const KEY_TASK string = "Task"
	const KEY_TASK_ID string = "TaskId"
	const KEY_STATUS_TEXT string = "StatusText"
	const KEY_RESULT string = "Result"
	// 状态值
	const STATUS_SUCCESS string = "SUCCESS"
	const STATUS_RUNNING string = "RUNNING"
	const STATUS_QUEUEING string = "QUEUEING"

	// 相比非STS模式,此时此处填写之前生成的STS临时访问凭证(含STS账号信息及SecurityToken)
	// 特别需要注意的是:临时访问凭证存在有效期,在有效期内您可以一直使用,但是请在过期前及时再次获取
	var accessKeyId string = "STS.******"
	var accessKeySecret string = "******"
	var stsToken string = ""******""
  var appKey string = "请填写您的appkey"

	var fileLink string = "https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav"
	client, err := sdk.NewClientWithStsToken(REGION_ID, accessKeyId, accessKeySecret, stsToken)
	if err != nil {
		panic(err)
	}
	postRequest := requests.NewCommonRequest()
	postRequest.Domain = DOMAIN
	postRequest.Version = API_VERSION
	postRequest.Product = PRODUCT
	postRequest.ApiName = POST_REQUEST_ACTION
	postRequest.Method = "POST"
	mapTask := make(map[string]string)
	mapTask[KEY_APP_KEY] = appKey
	mapTask[KEY_FILE_LINK] = fileLink
	// 新接入请使用4.0版本,已接入(默认2.0)如需维持现状,请注释掉该参数设置。
	mapTask[KEY_VERSION] = "4.0"
	// 设置是否输出词信息,默认为false。开启时需要设置version为4.0。
	mapTask[KEY_ENABLE_WORDS] = "false"
	task, err := json.Marshal(mapTask)
	if err != nil {
		panic(err)
	}
	postRequest.FormParams[KEY_TASK] = string(task)
	postResponse, err := client.ProcessCommonRequest(postRequest)
	if err != nil {
		panic(err)
	}
	postResponseContent := postResponse.GetHttpContentString()
	fmt.Println(postResponseContent)
	if postResponse.GetHttpStatus() != 200 {
		fmt.Println("录音文件识别请求失败,Http错误码: ", postResponse.GetHttpStatus())
		return
	}
	var postMapResult map[string]interface{}
	err = json.Unmarshal([]byte(postResponseContent), &postMapResult)
	if err != nil {
		panic(err)
	}
	var taskId string = ""
	var statusText string = ""
	statusText = postMapResult[KEY_STATUS_TEXT].(string)
	if statusText == STATUS_SUCCESS {
		fmt.Println("录音文件识别请求成功响应!")
		taskId = postMapResult[KEY_TASK_ID].(string)
	} else {
		fmt.Println("录音文件识别请求失败!")
		return
	}
	getRequest := requests.NewCommonRequest()
	getRequest.Domain = DOMAIN
	getRequest.Version = API_VERSION
	getRequest.Product = PRODUCT
	getRequest.ApiName = GET_REQUEST_ACTION
	getRequest.Method = "GET"
	getRequest.QueryParams[KEY_TASK_ID] = taskId
	statusText = ""
	for true {
		getResponse, err := client.ProcessCommonRequest(getRequest)
		if err != nil {
			panic(err)
		}
		getResponseContent := getResponse.GetHttpContentString()
		fmt.Println("识别查询结果:", getResponseContent)
		if getResponse.GetHttpStatus() != 200 {
			fmt.Println("识别结果查询请求失败,Http错误码:", getResponse.GetHttpStatus())
			break
		}
		var getMapResult map[string]interface{}
		err = json.Unmarshal([]byte(getResponseContent), &getMapResult)
		if err != nil {
			panic(err)
		}
		statusText = getMapResult[KEY_STATUS_TEXT].(string)
		if statusText == STATUS_RUNNING || statusText == STATUS_QUEUEING {
			time.Sleep(10 * time.Second)
		} else {
			break
		}
	}
	if statusText == STATUS_SUCCESS {
		fmt.Println("录音文件识别成功!")
	} else {
		fmt.Println("录音文件识别失败!")
	}
}

Node.js代码演示通过STS临时访问凭证调用录音文件识别服务

请您提前安装阿里云Core SDK、STS SDK及录音文件转写识别SDK,前两个SDK的安装,请参见Node.js SDK安装及示例。简单步骤如下:

npm install @alicloud/pop-core --save  
npm install @alicloud/sts-sdk --save   
npm install @alicloud/nls-filetrans-2018-08-17 --save

以下是Node.js代码演示通过STS临时访问凭证调用录音文件转写服务的完整示例:

'use strict';
const Client = require('@alicloud/nls-filetrans-2018-08-17');
function fileTrans(akID, akSecret, stsToken, appKey, fileLink) {
    //地域ID,固定值。
    var ENDPOINT = 'http://filetrans.cn-hangzhou.aliyuncs.com';
    var API_VERSION = '2018-08-17';
    /**
     * 创建阿里云鉴权client
     */
    var client = new Client({
        accessKeyId: akID, 
        secretAccessKey: akSecret,
        securityToken: stsToken,
        endpoint: ENDPOINT,
        apiVersion: API_VERSION
    });
    /**
     * 提交录音文件识别请求,请求参数组合成JSON格式的字符串作为task的值。
     * 请求参数appkey:项目appkey,获取Appkey请前往控制台:https://nls-portal.console.aliyun.com/applist
     * 请求参数file_link:需要识别的录音文件。
     */
    var task = {
        appkey : appKey,
        file_link : fileLink,
        version : "4.0",        // 新接入请使用4.0版本,已接入(默认2.0)如需维持现状,请注释掉该参数设置。
        enable_words : false     // 设置是否输出词信息,默认值为false,开启时需要设置version为4.0。
    };
    task = JSON.stringify(task);
    var taskParams = {
        Task : task
    };
    var options = {
            method: 'POST'
        };
    // 提交录音文件识别请求,处理服务端返回的响应。
    client.submitTask(taskParams, options).then((response) => {
        console.log(response);
        // 服务端响应信息的状态描述StatusText。
        var statusText = response.StatusText;
        if (statusText != 'SUCCESS') {
            console.log('录音文件识别请求响应失败!')
            return;
        }
        console.log('录音文件识别请求响应成功!');
        // 获取录音文件识别请求任务的TaskId,以供识别结果查询使用。
        var taskId = response.TaskId;
        /**
         * 以TaskId为查询参数,提交识别结果查询请求。
         * 以轮询的方式进行识别结果的查询,直到服务端返回的状态描述为"SUCCESS"、SUCCESS_WITH_NO_VALID_FRAGMENT,
         * 或者为错误描述,则结束轮询。
        */
        var taskIdParams = {
            TaskId : taskId
        };
        var timer = setInterval(() => {
            client.getTaskResult(taskIdParams).then((response) => {
                console.log('识别结果查询响应:');
                console.log(response);
                var statusText = response.StatusText;
                if (statusText == 'RUNNING' || statusText == 'QUEUEING') {
                    // 继续轮询,注意间隔周期。
                }
                else {
                    if (statusText == 'SUCCESS' || statusText == 'SUCCESS_WITH_NO_VALID_FRAGMENT') {
                        console.log('录音文件识别成功:');
                        var sentences = response.Result;
                        console.log(sentences);
                    }
                    else {
                        console.log('录音文件识别失败!');
                    }
                    // 退出轮询
                    clearInterval(timer);
                }
            }).catch((error) => {
                console.error(error);
                // 异常情况,退出轮询。
                clearInterval(timer);
            });
        }, 10000);
    }).catch((error) => {
        console.error(error);
    });
}

// 相比非STS模式,此时此处填写之前生成的STS临时访问凭证(含STS账号信息及SecurityToken)
// 特别需要注意的是:临时访问凭证存在有效期,在有效期内您可以一直使用,但是请在过期前及时再次获取
var akId = 'STS.******';
var akSecret = '******';
var stsToken = '******';
var appKey = '请填写您的appkey';
var fileLink = 'https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav';

fileTrans(akId, akSecret, stsToken, appKey, fileLink);

PHP代码演示通过STS临时访问凭证调用录音文件识别服务

请您提前安装阿里云Core SDK、STS SDK的PHP语言版本,详细安装请参见Node.js SDK安装及示例。简单步骤如下:

composer require alibabacloud/sdk
composer require alibabacloud/sts

以下是PHP代码演示通过STS临时访问凭证调用录音文件识别服务的完整示例:

<?php
require __DIR__ . '/vendor/autoload.php';
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;

class NLSFileTrans {
    // 请求参数
    private const KEY_APP_KEY = "appkey";
    private const KEY_FILE_LINK = "file_link";
    private const KEY_VERSION = "version";
    private const KEY_ENABLE_WORDS = "enable_words";
    // 响应参数
    private const KEY_TASK_ID = "TaskId";
    private const KEY_STATUS_TEXT = "StatusText";
    private const KEY_RESULT = "Result";
    // 状态值
    private const STATUS_SUCCESS = "SUCCESS";
    private const STATUS_RUNNING = "RUNNING";
    private const STATUS_QUEUEING = "QUEUEING";

    function submitFileTransRequest($appKey, $fileLink) {
        // 获取task JSON字符串,包含appkey和file_link参数等。
        $taskArr = array(self::KEY_APP_KEY => $appKey, self::KEY_FILE_LINK => $fileLink, self::KEY_VERSION => "4.0", self::KEY_ENABLE_WORDS => FALSE);
        $task = json_encode($taskArr);
        print $task . "\n";
        try {
            // 提交请求,返回服务端的响应。
            $submitTaskResponse = AlibabaCloud::nlsFiletrans()
                                              ->v20180817()
                                              ->submitTask()
                                              ->host("filetrans.cn-shanghai.aliyuncs.com")
                                              ->withTask($task)
                                              ->request();

            print $submitTaskResponse . "\n";
            // 获取录音文件识别请求任务的ID,以供识别结果查询使用。
            $taskId = NULL;
            $statusText = $submitTaskResponse[self::KEY_STATUS_TEXT];
            if (strcmp(self::STATUS_SUCCESS, $statusText) == 0) {
                $taskId = $submitTaskResponse[self::KEY_TASK_ID];
            }
            return $taskId;
        } catch (ClientException $exception) {
            // 获取错误消息
            print_r($exception->getErrorMessage());
        } catch (ServerException $exception) {
            // 获取错误消息
            print_r($exception->getErrorMessage());
        }
    }
    function getFileTransResult($taskId) {
        $result = NULL;
        while (TRUE) {
            try {
                $getResultResponse = AlibabaCloud::nlsFiletrans()
                                                 ->v20180817()
                                                 ->getTaskResult()
                                                 ->host("filetrans.cn-shanghai.aliyuncs.com")
                                                 ->withTaskId($taskId)
                                                 ->request();
                print "识别查询结果: " . $getResultResponse . "\n";
                $statusText = $getResultResponse[self::KEY_STATUS_TEXT];
                if (strcmp(self::STATUS_RUNNING, $statusText) == 0 || strcmp(self::STATUS_QUEUEING, $statusText) == 0) {
                    // 继续轮询
                    sleep(10);
                }
                else {
                    if (strcmp(self::STATUS_SUCCESS, $statusText) == 0) {
                        $result = $getResultResponse;
                    }
                    // 退出轮询
                    break;
                }
            } catch (ClientException $exception) {
                // 获取错误消息
                print_r($exception->getErrorMessage());
            } catch (ServerException $exception) {
                // 获取错误消息
                print_r($exception->getErrorMessage());
            }
        }
        return $result;
    }
}
$accessKeyId = "STS.******";
$accessKeySecret = "******";
$stsToken = "******";
$appKey = "请填写您的appkey";
$fileLink = "https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav";
/**
  * 第一步:设置一个全局客户端。
  * 使用阿里云RAM账号的AccessKey ID和AccessKey Secret进行鉴权。
 */
Alibabacloud::stsClient($accessKeyId, $accessKeySecret, $stsToken)
                ->regionId("cn-shanghai")
                ->asGlobalClient();

$fileTrans = new NLSFileTrans();
/**
  *  第二步:提交录音文件识别请求,获取任务ID,用于后续的识别结果轮询。
 */
$taskId = $fileTrans->submitFileTransRequest($appKey, $fileLink);
if ($taskId != NULL) {
    print "录音文件识别请求成功,task_id: " . $taskId . "\n";
}
else {
    print "录音文件识别请求失败!";
    return ;
}
/**
  * 第三步:根据任务ID轮询识别结果。
 */
$result = $fileTrans->getFileTransResult($taskId);
if ($result != NULL) {
    print "录音文件识别结果查询成功: " . $result . "\n";
}
else {
    print "录音文件识别结果查询失败!";
}