Aprenda cómo la API Realtime autentica las conexiones con tokens, incluyendo cómo obtener una clave de API y cómo autenticarse mediante los protocolos WebSocket, WebRTC y AOQ.
Métodos de autenticación
La API Realtime utiliza claves de API para la autenticación. Ya sea que se conecte mediante AOQ, WebRTC o WebSocket, debe pasar un token portador en el encabezado de solicitud HTTP Authorization.
La autenticación ocurre solo durante la configuración de la conexión. Una vez establecida la conexión, la transmisión de datos no requiere reautenticación.
La siguiente tabla compara cómo se autentican los tres protocolos:
Protocolo | Cuándo ocurre la autenticación | Método de autenticación | Notas |
|---|---|---|---|
AOQ | Cuando el AppServer empresarial solicita al gateway | Encabezado HTTP | La clave de API se utiliza únicamente en el lado del servidor. El cliente utiliza el token devuelto por la puerta de enlace |
WebRTC | Durante la solicitud HTTP de intercambio SDP | Encabezado HTTP | El cliente o servidor inicia el intercambio SDP con la clave de API |
WebSocket | Durante el protocolo de enlace de WebSocket | Encabezado HTTP | El cliente o servidor se conecta directamente con la clave de API |
Obtener una clave de API
Paso 1: Activar Model Studio
- Vaya a la consola de Alibaba Cloud Model Studio e inicie sesión con su cuenta de Alibaba Cloud.
- Si es la primera vez que utiliza el servicio, siga las instrucciones en pantalla para activarlo.
Paso 2: Crear una clave de API
- En el panel de navegación izquierdo de la consola, seleccione API Key.
- Haga clic en Create API Key y seleccione el espacio de trabajo para asociar con la clave.
- Una vez creada la clave, cópiela y guárdela inmediatamente.
ImportanteNota de seguridad: La clave de API es su única credencial para acceder al servicio. No la codifique directamente en el código del cliente ni la confirme en un repositorio de código. Gestiónele mediante variables de entorno o distribúyala desde un servicio backend.
Detalles de autenticación de conexión
Autenticación del protocolo AOQ
AOQ utiliza un modelo de autenticación proxy del lado del servidor: la clave de API se utiliza únicamente en el AppServer empresarial. El cliente se conecta con un token temporal devuelto por la puerta de enlace, lo que mantiene la clave de API fuera del cliente.
Para el acceso AOQ, seleccione la ruta de solicitud de conexión según la serie del modelo. Para consultar la compatibilidad de protocolos por modelo, vea Resumen de la API Realtime.
| Serie de modelos | Ruta de solicitud de conexión |
|---|---|
| Qwen-Omni-Realtime, Qwen-Audio-Realtime, Qwen-Livetranslate-Realtime | /api/v1/webrtc/realtime |
| Qwen-Audio-TTS, CosyVoice, Qwen-Audio-ASR-Streaming, Qwen-Audio-ASR-Message, Fun-ASR-Realtime | /api/v1/webrtc/inference |
El siguiente ejemplo de Realtime utiliza qwen3.8-omni-flash-realtime. Establezca {endpoint} en {WorkspaceId}.cn-beijing.maas.aliyuncs.com para China (Beijing) o {WorkspaceId}.ap-southeast-1.maas.aliyuncs.com para Singapur. Reemplace {WorkspaceId} con su ID de espacio de trabajo y utilice la clave de API correspondiente a la misma región y espacio de trabajo.
curl -X POST \
"https://{endpoint}/api/v1/webrtc/realtime?model=qwen3.8-omni-flash-realtime" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${DASHSCOPE_API_KEY}" \
-H "x-dashscope-rtc-transport: moq" \
-d "{\"clientIp\": \"${CLIENT_REAL_IP}\"}"
curl -X POST \
"https://{endpoint}/api/v1/webrtc/inference?model=fun-asr-realtime" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${DASHSCOPE_API_KEY}" \
-H "x-dashscope-rtc-transport: moq" \
-d "{\"clientIp\": \"${CLIENT_REAL_IP}\"}"
Campos de solicitud
Elemento | Valor | Descripción |
|---|---|---|
endpoint | Seleccione un dominio de acceso según su escenario empresarial | Especifica el dominio de acceso. Para más detalles, consulte Regiones y dominios de acceso. Si utiliza Token Plan, el |
Content-Type |
| Especifica el tipo de mensaje |
Authorization |
| Su clave de API |
x-dashscope-rtc-transport |
| Especifica el protocolo AOQ |
clientIp | La dirección IP pública real del cliente | Opcional. Si no se especifica, se utiliza la dirección IP que solicita la puerta de enlace de Model Studio. Si se especifica, el valor clientIp tiene prioridad. La API Realtime asigna el mejor punto de acceso Relay basándose en la dirección IP del cliente |
Ejemplo de respuesta
{
"sid": "1d06b55683db49bba67a407902f62d02:1782706970:69aecdc5...",
"aoqTokenForClient": "ecc1a46015d5496ca4ff7a48281eb739",
"clientRelayEndpoints": [{"endpoint": "121.199.XX.XX", "port": 8443, "route_index": 0}],
"clientRelayCertFingerprint": "sha256/99843495...",
"sidExpiresInSecs": 7200,
"extraInfo": {"workspaceIdHash": "2021b6f98cea4cff"}
}
Campos de respuesta
Campo | Descripción |
|---|---|
sid | ID de sesión único |
aoqTokenForClient | Token de conexión del cliente. Páselo al campo token del SDK |
clientRelayEndpoints | Matriz de puntos de acceso de retransmisión (endpoint + puerto) |
clientRelayCertFingerprint | Huella digital del certificado TLS de retransmisión |
sidExpiresInSecs | Tiempo de expiración de la sesión, en segundos |
extraInfo.workspaceIdHash | Hash del ID del espacio de trabajo |
Ejemplo de conexión del SDK de cliente AOQ
NotaclientIp es un campo opcional en el cuerpo de la solicitud. Si no se especifica, la dirección IP que solicita la puerta de enlace de Model Studio se utiliza como la IP del cliente. Si se especifica, el valor clientIp tiene prioridad. Haga que su AppServer empresarial obtenga la dirección IP real del cliente y pásela para obtener el mejor punto de acceso Relay.
let resp = try JSONDecoder().decode(AllocateResponse.self, from: responseData)
let config = AoqConnectConfig()
config.token = resp.aoqTokenForClient
config.sid = resp.sid
config.certFingerprint = resp.clientRelayCertFingerprint
config.relayEndpoints = resp.clientRelayEndpoints.enumerated().map { index, item in
let ep = AoqRelayEndpoint()
// Fall back to the array index when route_index is missing
ep.routeIndex = item.routeIndex ?? index
ep.endpoint = item.endpoint
ep.port = item.port
return ep
}
config.workspaceIdHash = resp.extraInfo?.workspaceIdHash ?? ""
let audioTrack = AoqTrackParam()
audioTrack.trackType = .audio
let dataTrack = AoqTrackParam()
dataTrack.trackType = .data
config.publishTracks = [audioTrack, dataTrack]
config.subscribeTracks = [audioTrack, dataTrack]
engine.connect(config)
JSONObject obj = new JSONObject(responseText);
AoqClientEngine.AoqConnectConfig cfg = new AoqClientEngine.AoqConnectConfig();
cfg.token = obj.optString("aoqTokenForClient", "");
cfg.sid = obj.optString("sid", "");
cfg.certFingerprint = obj.optString("clientRelayCertFingerprint", "");
JSONArray arr = obj.optJSONArray("clientRelayEndpoints");
if (arr != null) {
for (int i = 0; i < arr.length(); i++) {
JSONObject o = arr.optJSONObject(i);
AoqClientEngine.AoqRelayEndpoint ep = new AoqClientEngine.AoqRelayEndpoint();
// Fall back to the array index when route_index is missing
ep.routeIndex = o.has("route_index") ? o.optInt("route_index", i) : i;
ep.endpoint = o.optString("endpoint", "");
ep.port = o.optInt("port", 0);
cfg.relayEndpoints.add(ep);
}
}
JSONObject ext = obj.optJSONObject("extraInfo");
cfg.workspaceIdHash = ext != null ? ext.optString("workspaceIdHash", "") : "";
AoqClientEngine.AoqTrackParam audio = new AoqClientEngine.AoqTrackParam();
audio.trackType = AoqClientEngine.AoqTrackType.AoqTrackTypeAudio;
AoqClientEngine.AoqTrackParam data = new AoqClientEngine.AoqTrackParam();
data.trackType = AoqClientEngine.AoqTrackType.AoqTrackTypeData;
cfg.publishTracks.add(audio);
cfg.publishTracks.add(data);
cfg.subscribeTracks.add(audio);
cfg.subscribeTracks.add(data);
engine.connect(cfg);
const obj = JSON.parse(responseText) as Record<string, Object | undefined>;
const cfg: AoqConnectConfig = {
token: String(obj['aoqTokenForClient'] ?? ''),
sid: String(obj['sid'] ?? ''),
certFingerprint: String(obj['clientRelayCertFingerprint'] ?? ''),
// Fall back to the array index when route_index is missing
relayEndpoints: (obj['clientRelayEndpoints'] as Array<any>).map((item, index) => ({
routeIndex: Number(item['route_index'] ?? index),
endpoint: String(item['endpoint'] ?? ''),
port: Number(item['port'] ?? 0)
})),
workspaceIdHash: String((obj['extraInfo'] as any)?.['workspaceIdHash'] ?? ''),
publishTracks: [
{ trackType: AoqTrackType.AoqTrackTypeAudio },
{ trackType: AoqTrackType.AoqTrackTypeData }
],
subscribeTracks: [
{ trackType: AoqTrackType.AoqTrackTypeAudio },
{ trackType: AoqTrackType.AoqTrackTypeData }
]
};
engine.connect(cfg);
Autenticación del protocolo WebRTC
WebRTC completa el intercambio SDP mediante una solicitud HTTP POST, y la autenticación ocurre en esta etapa. El cliente envía el Offer SDP al servidor, y el servidor devuelve el Answer SDP.
Elemento | Valor | Descripción |
|---|---|---|
Método de solicitud | POST | - |
URL de solicitud |
| Reemplace endpoint y model_name. La URL de conexión varía según el modelo. Para más detalles, consulte Conexión WebRTC |
Content-Type |
| El cuerpo de la solicitud es una cadena SDP |
Authorization |
| Su clave de API |
Respuesta | HTTP 200 con el SDP de respuesta | Devuelve un código de estado 4xx en caso de error |
const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
stream.getAudioTracks().forEach(t => pc.addTrack(t, stream));
pc.createDataChannel('oai-events');
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// Send after ICE gathering is complete
const resp = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/sdp',
'Authorization': `Bearer ${API_KEY}`,
},
body: pc.localDescription.sdp,
});
const answerSdp = await resp.text();
await pc.setRemoteDescription({ type: 'answer', sdp: answerSdp });
Autenticación del protocolo WebSocket
WebSocket tiene la autenticación más sencilla: envíe la clave de API en un encabezado HTTP al establecer la conexión.
Elemento | Valor | Descripción |
|---|---|---|
URL de conexión |
| La URL de conexión varía según el modelo. Para más detalles, consulte Conexión WebSocket |
Authorization |
| Su clave de API |
import websocket, os
API_KEY = os.getenv("DASHSCOPE_API_KEY")
URL = "wss://dashscope.aliyuncs.com/api-ws/v1/realtime?model=qwen3.5-omni-plus-realtime"
ws = websocket.WebSocketApp(URL, header=["Authorization: Bearer " + API_KEY])
ws.run_forever()