Server-side Authorization

更新时间:
复制 MD 格式

This document describes the interfaces and provides sample code for authenticating speech evaluation, essay grading, and AI teacher services.

Important

For security and ease of maintenance, you must integrate this step on the server-side. This prevents key leakage and associated security vulnerabilities.

Note

RAM users require the AliyunAIContentFullAccess permission to invoke this service.

Speech Evaluation Authorization and Request Flow

image

  1. The evaluation device initiates an authorization request

    • The evaluation device sends a POST request to your server to request pre-evaluation authorization.

  2. Your server authenticates the user and requests authorization

    • After your server receives the request from the evaluation device, it authenticates the user.

    • After the user is authenticated, your server sends an authorization request to the speech evaluation authorization service.

  3. Obtain the authorization ID

    • After the request is processed, the speech evaluation authorization service returns an authorization ID (warrant_id) to your server. This authorization ID can be used multiple times during its validity period.

  4. Pass the authorization ID to the evaluation device

    • After your server receives the authorization ID, it returns the ID to the evaluation device.

  5. Assemble and send the evaluation request

    • The evaluation device assembles a data packet in JSON format as specified by the evaluation request interface.

    • The evaluation device then uses the authorization ID and other required information to send an evaluation request to the evaluation server.

  6. Receive the evaluation results

    • The evaluation server processes the request and returns the evaluation results to the evaluation device in JSON format.

  7. Service Presentation

    • Finally, the evaluation device uses the evaluation results to update the business logic or user interface, which completes the process.

Authentication Interface Requests

Request Addresses

    https://api.cloud.ssapi.cn/auth/authorize
    https://gate-01.api.cloud.ssapi.cn/auth/authorize
    https://gate-02.api.cloud.ssapi.cn/auth/authorize
    https://gate-03.api.cloud.ssapi.cn/auth/authorize

Request Method

Send the request using a form POST.

Request Parameters

Parameter Name

Type

Is it mandatory?

Default Value

Description

appid

string

Y

None

Obtain this from the console after placing an order on the Alibaba Cloud official website. For non-official website orders, contact your service representative.

timestamp

string

Y

None

The timestamp (10-digit UNIX timestamp in seconds) when you initiate the authorization request.

user_id

string

Y

string

The unique identifier for your product's user system. This can be a user ID or device ID. Ensure it remains unique.

Note that this user ID must match the user ID passed during evaluation; otherwise, evaluation may not function correctly.

user_client_ip

ip string

Y

None

The public network IP address of the client device.

request_sign

string

Y

None

The signature for the authorization interface parameters. MD5 encrypt the parameters in the following order;

  1. app_secret

  2. appid

  3. timestamp

  4. user_client_ip

  5. user_id

For a code example, see Signature logic example for requesting authorization.

warrant_available

integer

N

7200

The time-to-live (TTL) for the authorization ID, in seconds.

Important
  • appid and app_secret: You can obtain these credentials from the console after you purchase the service on the Alibaba Cloud website. If you purchased the service through other channels, contact your service representative.

  • The app_secret is a critical credential. You must store it in a secure runtime environment and not include it in authorization requests.

Response Parameters

Parameter Name

Type

Is this required?

Default Value

Description

code

integer

Y

0

Status code: 0: Success

msg

string

Y

success

Status description: success: Success

data.warrant_id

string

Y

string

The authorization ID returned by the platform.

data.expire_at

timestamp

Y

time()+7200

The authorization ID expiration time, default 2 hours.

Error Codes

Error Code

Location

Error Description

430001

Platform

When requesting the platform, no parameters were passed.

430002

Platform

When requesting the platform, the timestamp parameter was not passed.

430003

Platform

When requesting the platform, the request_sign parameter was not passed.

430004

Platform

When requesting the platform, the appid parameter was not passed.

430005

Platform

When requesting the platform, the appid is invalid.

430006

Platform

When requesting the platform, the user_id parameter was not passed.

430007

Platform

When requesting the platform, the user_client_ip parameter was not passed.

430008

Platform

When requesting the platform, the request_sign failed authentication; the signature is incorrect. If requesting the staging environment, modify it according to the returned information.

430009

Platform

The platform authentication server crashed.

Examples

Request Authorization

curl

curl -X POST \
  https://api.cloud.ssapi.cn/auth/authorize \
  -F "appid=your_appid" \
  -F "timestamp=$(date +%s)" \
  -F "user_id=your_user_id" \
  -F "user_client_ip=your_client_ip" \
  -F "request_sign=your_request_sign" \
  -F "warrant_available=7200"

Replace the parameters in the example with your actual values. The `$(date +%s)` command retrieves the real-time timestamp.

Authorization Response

{
  "code": 0,
  "message": "success",
  "data": {
    "warrant_id": "5aec3959f4130352bf067fd21f019",
    "expire_at": 1525430617,
    "timestamp": "1525423417"
  }
}

Signature Logic Example for Requesting Authorization

PHP

$data = ['appid' => $app_id, 'timestamp' => $timestamp, 'user_id' => $user_id, 'user_client_ip' => $user_client_ip, 'app_secret' => $app_secret];
ksort($data);

$data_kv = [ ];

foreach ($data as $k => $v) {
  array_push($data_kv, $k.'='.$v);
}
$sign_string = implode('&', $data_kv);
$new_sign = md5($sign_string);

JAVA

import java.security.MessageDigest;
import java.util.*;

// Java version of signature generation code
Map<String, Object> data = new HashMap<>();
data.put("appid", app_id);
data.put("timestamp", timestamp);
data.put("user_id", user_id);
data.put("user_client_ip", user_client_ip);
data.put("app_secret", app_secret);

List<Map.Entry<String, Object>> list = new ArrayList<>(data.entrySet());
Collections.sort(list, Map.Entry.comparingByKey());

StringBuilder signString = new StringBuilder();
for (Map.Entry<String, Object> entry : list) {
    signString.append(entry.getKey()).append("=").append(entry.getValue().toString()).append("&");
}

String sign = signString.toString().substring(0, signString.length() - 1); // Remove the last extra "&"

try {
    MessageDigest md = MessageDigest.getInstance("MD5");

    byte[ ] digest = md.digest(sign.getBytes());

    StringBuilder hexString = new StringBuilder();

    for (byte b : digest) {
        hexString.append(String.format("%02x", b));
    }

    String newSign = hexString.toString(); // MD5 signature
} catch (Exception e) {
    e.printStackTrace();
}

Python

from hashlib import md5

def generate_signature(app_id, timestamp, user_id, user_client_ip, app_secret):
  """
  Generate the signature string based on the given parameters.
  """
  params = {'appid': app_id, 'timestamp': str(timestamp),'user_id': user_id, 'user_client_ip': user_client_ip,'app_secret': app_secret}
  sorted_params = dict(sorted(params.items()))
  query_string = '&'.join([f"{k}={v}" for k, v in sorted_params.items()])
  signature = md5(query_string.encode()).hexdigest()
  return signature

# Example
app_id = 'a111'
timestamp = 1603885321
user_id = 'w9egtDf3PMAOaxZVGSlQUip12no6WCvu'
user_client_ip = '111.111.XXX.XXX'
app_secret = 'wHkC1SMmDLrVO86vcydG2ax4oPYuqiIh'

print(generate_signature(app_id, timestamp, user_id, user_client_ip, app_secret))```

Complete Example

This section provides a complete example that shows the logic for reading keys from environment variables, address polling, signing requests, and obtaining authorization.

Go Language

package main

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"sort"
	"time"
)

func main() {
	appId := os.Getenv("APP_ID")
	appSecret := os.Getenv("APP_SECRET")
	timestamp := fmt.Sprintf("%d", time.Now().Unix())
	userClientIp := "172.26.1.61" // Replace with the actual public network IP address of the client.
	userID := "dummyUserId"       // Replace with the actual user ID.

	signature := generateSignature(appId, timestamp, userID, userClientIp, appSecret)
	fmt.Printf("signature=%s\n\n", signature)


	urls := [ ]string{

		// Staging environment
		"http://ginger-trial.api.cloud.ssapi.cn:8080/auth/authorize",
		// Production environment
		//"https://api.cloud.ssapi.cn/auth/authorize",
		//"https://gate-01.api.cloud.ssapi.cn/auth/authorize",
		//"https://gate-02.api.cloud.ssapi.cn/auth/authorize",
		//"https://gate-03.api.cloud.ssapi.cn/auth/authorize",
	}
	for _, url := range urls {
		respBody, err := requestAuthorization(url, appId, timestamp, userID, userClientIp, signature)
		if err == nil {

			fmt.Println("Authorization Done")
			// Construct a JSON string containing the authorization ID.
			var result struct {
				Code int    `json:"code"`
				Msg  string `json:"msg"`
				Data struct {
					WarrantId string `json:"warrant_id"`
					ExpireAt  int64  `json:"expire_at"`
				} `json:"data"`
			}

			// Parse JSON data

			if err := json.NewDecoder(bytes.NewBuffer([ ]byte(respBody))).Decode(&result); err == nil {

				// Print parsed data
				fmt.Printf("Status Code: %d\n", result.Code)
				fmt.Printf("Status Description: %s\n", result.Msg)
				fmt.Printf("Authorization ID: %s\n", result.Data.WarrantId)
				fmt.Printf("Authorization ID Expiration Time: %d\n", result.Data.ExpireAt)
			} else {
				// Handle parsing errors
				fmt.Printf("JSON parsing failed: %v\n", err)
				// Output resp.Body content as a string
				fmt.Printf("Response Body Content:%s;;;\n", respBody)
			}
			break
		}
		time.Sleep(time.Second * 2) // Polling interval
	}
}

func generateSignature(appId, timestamp, userId, userClientIp, appSecret string) string {
	data := map[string]string{
		"appid":          appId,
		"timestamp":      timestamp,
		"user_id":        userId,
		"user_client_ip": userClientIp,
		"app_secret":     appSecret,
	}


	var keys [ ]string

	for key := range data {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	var buf bytes.Buffer
	for _, key := range keys {
		buf.WriteString(key + "=" + data[key] + "&")
	}
	buf.Truncate(buf.Len() - 1) // Remove the last extra "&"

	hash := md5.New()

	hash.Write([ ]byte(buf.String()))


	return hex.EncodeToString(hash.Sum(nil))
}

func requestAuthorization(url, appId, timestamp, userID, clientIp, signature string) (string, error) {
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	_ = writer.WriteField("appid", appId)
	_ = writer.WriteField("timestamp", timestamp)
	_ = writer.WriteField("user_id", userID)
	_ = writer.WriteField("user_client_ip", clientIp)
	_ = writer.WriteField("request_sign", signature)
	_ = writer.WriteField("warrant_available", "7200")

	err := writer.Close()
	if err != nil {
		return "", err
	}

	req, _ := http.NewRequest("POST", url, body)
	req.Header.Set("Content-Type", writer.FormDataContentType())

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil || resp.StatusCode != http.StatusOK {
		return "", err
	}
	bodyBytes, _ := io.ReadAll(resp.Body)
	fmt.Printf("Response Body Content:%s;;;\n", string(bodyBytes))
	return string(bodyBytes), err
}

Python Language

import os
import time

import requests
from hashlib import md5

# Get sensitive information from environment variables
app_id = os.getenv('APP_ID')
app_secret = os.getenv('APP_SECRET')

# Other required parameters
timestamp = int(time.time())
user_id = 'your_user_id'
user_client_ip = '192.168.0.1'


# Signature generation function
def generate_signature(app_id, timestamp, user_id, user_client_ip, app_secret):
    params = {
        'appid': app_id,
        'timestamp': str(timestamp),
        'user_id': user_id,
        'user_client_ip': user_client_ip,
        'app_secret': app_secret
    }

    sorted_params = dict(sorted(params.items()))
    query_string = '&'.join(f'{k}={v}' for k, v in sorted_params.items())
    return md5(query_string.encode()).hexdigest()


signature = generate_signature(app_id, timestamp, user_id, user_client_ip, app_secret)

# Request URL list
urls = [
    #
    'http://trial.cloud.ssapi.cn:8080/auth/authorize',
    # Production environment
    # 'https://api.cloud.ssapi.cn/auth/authorize',
    # 'https://gate-01.api.cloud.ssapi.cn/auth/authorize',
    # 'https://gate-02.api.cloud.ssapi.cn/auth/authorize',
    # 'https://gate-03.api.cloud.ssapi.cn/auth/authorize'
]

# Send request and process response
for url in urls:
    response = requests.post(
        url=url,
        data={
            'appid': app_id,
            'timestamp': str(timestamp),
            'user_id': user_id,
            'user_client_ip': user_client_ip,
            'request_sign': signature,
            'warrant_available': '7200'
        },
        headers={'Content-Type': 'application/x-www-form-urlencoded'}
    )

    if response.status_code == 200:
        print("Original result: " + str(response.content))
        result = response.json()

        if result['code'] == 0:
            print(f"warrant_id: {result['data']['warrant_id']}")
            print(f"Expiration time: {result['data']['expire_at']}")

            break

Java Language

First, import the following Maven dependency:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
</dependency>
package com.alibaba.edu.efec.demo;

import com.alibaba.fastjson.JSONObject;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;

public class TestGetWarrant {


    public static void main(String[ ] args) throws IOException {

        // Get sensitive information from environment variables
        String app_id = System.getenv("APP_ID");
        String app_secret = System.getenv("APP_SECRET");

        // Other required parameters
        long timestamp = System.currentTimeMillis() / 1000L;
        String user_id = "your_user_id";
        String user_client_ip = "192.168.0.1";

        // Signature generation function
        String signature = generateSignature(app_id, timestamp, user_id, user_client_ip, app_secret);

        // Request URL list
        List<String> urls = Arrays.asList(
                "http://trial.cloud.ssapi.cn:8080/auth/authorize"
                // Production environment
                // "https://api.cloud.ssapi.cn/auth/authorize",
                // "https://gate-01.api.cloud.ssapi.cn/auth/authorize",
                // "https://gate-02.api.cloud.ssapi.cn/auth/authorize",
                // "https://gate-03.api.cloud.ssapi.cn/auth/authorize"
        );

        // Send request and process response
        for (String urlStr : urls) {
            try {
                HttpURLConnection connection = (HttpURLConnection) new URL(urlStr).openConnection();
                connection.setRequestMethod("POST");
                connection.setDoOutput(true);
                connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

                Map<String, Object> params = new HashMap<>();
                params.put("appid", app_id);
                params.put("timestamp", timestamp);
                params.put("user_id", user_id);
                params.put("user_client_ip", user_client_ip);
                params.put("request_sign", signature);
                params.put("warrant_available", "7200");

                StringBuilder postData = new StringBuilder();
                for (Map.Entry<String, Object> param : params.entrySet()) {
                    if (postData.length() != 0) postData.append('&');
                    postData.append(param.getKey());
                    postData.append('=');
                    postData.append(URLEncoder.encode(String.valueOf(param.getValue()), StandardCharsets.UTF_8.toString()));
                }


                byte[ ] postDataBytes = postData.toString().getBytes(StandardCharsets.UTF_8);

                connection.getOutputStream().write(postDataBytes);

                int status = connection.getResponseCode();

                if (status == 200) {
                    Scanner scanner = new Scanner(connection.getInputStream(), String.valueOf(StandardCharsets.UTF_8));
                    StringBuilder body = new StringBuilder();
                    while (scanner.hasNextLine()) {
                        String line = scanner.nextLine();
                        System.out.println(line);
                        body.append(line);
                    }
                    scanner.close();

                    // Parse JSON response
                    JSONObject json = JSONObject.parseObject(body.toString());
                    if (json.getInteger("code") == 0) {
                        System.out.println("warrant_id: " + json.getJSONObject("data").getString("warrant_id"));
                        System.out.println("Expiration time: " + json.getJSONObject("data").getString("expire_at"));

                        break;
                    }


                } else {
                    throw new RuntimeException("Failed : HTTP error code : " + status);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static String generateSignature(String app_id, long timestamp, String user_id, String user_client_ip, String app_secret) {
        Map<String, String> params = new TreeMap<>();
        params.put("appid", app_id);
        params.put("timestamp", Long.toString(timestamp));
        params.put("user_id", user_id);
        params.put("user_client_ip", user_client_ip);
        params.put("app_secret", app_secret);

        StringBuilder queryString = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (queryString.length() > 0) {
                queryString.append("&");
            }
            queryString.append(entry.getKey()).append("=").append(entry.getValue());
        }

        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");

            byte[ ] hash = digest.digest(queryString.toString().getBytes(StandardCharsets.UTF_8));

            StringBuilder hexString = new StringBuilder();
            for (byte b : hash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

Error Codes

errorId

Description

Cause

Application layer recommendations

40092

The audio duration exceeds the limit.

The server limits the recording duration for each request.

Ensure that the recording duration is within the specified range.

41008

Audio format not supported.

The audio format is not supported.

Ensure that you use a supported audio format.

41010

Invalid audio information.

The channel in the audio information is missing or not supported. Only a value of 1 is supported.

The audio channel parameter does not exist or is not supported.

41016

SDK information is empty.

The sdk field is missing from connect.param.

Check whether the connect package is complete.

41017

The sdk object is missing the version field.

The version field is missing from connect.param.sdk.

Check whether the connect package is complete.

41018

The sdk object is missing the source field.

The source field is missing from connect.param.sdk.

Check whether the connect package is complete.

41019

The sdk object is missing the protocol field.

The protocol field is missing from connect.param.sdk.

Check whether the connect package is complete.

41030

Authentication failed.

The warrantId is missing or incorrect.

Check whether the warrantId was passed. Ensure that the userId used to obtain the warrantId matches the one used for the evaluation.

41035

Coretype not supported.

An unauthorized coretype was used.

Contact your sales representative to confirm that the coretype is enabled.

41036

The client concurrency limit is exceeded.

The number of concurrent evaluations has reached the purchased limit.

Contact your sales representative to confirm whether your purchased concurrency quota is sufficient.

42003

The client sent requests out of order.

The SDK was not invoked in the correct sequence.

Check whether the SDK is used correctly.

430005

Invalid appid.

An incorrect appid was used.

Confirm that the appid is valid and matches the environment. For example, test accounts require the staging environment.

51000

Kernel initialization failed.

The kernel returned an error when text parameters were passed to it.

Confirm that the parameters are passed in the correct format. If the issue persists, contact technical support.

53000

Kernel process crashed.

The kernel process crashed. This may be caused by an issue in the kernel code or by incorrect parameters passed from the SDK.

If you have confirmed that the parameter format is correct, contact technical support.

70001

The SDK version needs to be upgraded.

This SDK version is prohibited or has limited support.

You can contact Technical Support for assistance with the SDK.