请求地址

http请求地址:

视具体的ai能力而定
 http://api.xf-yun.com/v1/private/Service_ID

websocket请求地址:

视具体的ai能力而定
 wss://api.xf-yun.com/v1/private/Service_ID

其中Service_ID为创建AI能力生产的能力ID

握手&鉴权

websocket和http协议均需要进行签名,websocket在握手阶段,请求方需要对请求进行签名,服务端通过签名来校验请求的合法性,其中websocket协议为GET请求,http协议为POST请求。以下示例均为websocket协议,如能力为http协议,请更换为POST请求

鉴权方法:通过在请求地址后面加上鉴权相关参数的方式。 ws示例url:

wss://api.xf-yun.com/v1/private/Service_ID?authorization=YXBpX2tleT0ia2V5eHh4eHh4eHg4ZWUyNzkzNDg1MTlleHh4eHh4eHgiLCBhbGdvcml0aG09ImhtYWMtc2hhMjU2IiwgaGVhZGVycz0iaG9zdCBkYXRlIHJlcXVlc3QtbGluZSIsIHNpZ25hdHVyZT0iSHAzVHk0WmtTQm1MOGpLeU9McFFpdjlTcjVudm1lWUVIN1dzTC9aTzJKZz0i&date=Wed%2C%2010%20Jul%202019%2007%3A35%3A43%20GMT&host=api.xf-yun.com

http示例url:

https://api.xf-yun.com/v1/private/Service_ID?authorization=YXBpX2tleT0ia2V5eHh4eHh4eHg4ZWUyNzkzNDg1MTlleHh4eHh4eHgiLCBhbGdvcml0aG09ImhtYWMtc2hhMjU2IiwgaGVhZGVycz0iaG9zdCBkYXRlIHJlcXVlc3QtbGluZSIsIHNpZ25hdHVyZT0iNFZza0lKSDNVUkM0L2ZwYlgvRnJ1bU9ISHVCU2svZUdsVXYrUmtmeUcxOD0i&host=api.xf-yun.com&date=Tue%2C+22+Dec+2020+06%3A22%3A46+GMT

鉴权参数

参数 类型 必须 说明 示例
host string 请求主机 api.xf-yun.com
date string 当前时间戳,RFC1123格式(Wed, 10 Jul 2019 07:35:43 GMT) Wed, 10 Jul 2019 07:35:43 GMT
authorization string 使用base64编码的签名相关信息(签名基于hmac-sha256计算) 参考下方authorization参数生成规则

· date参数生成规则

date必须是UTC+0或GMT时区,RFC1123格式(Wed, 10 Jul 2019 07:35:43 GMT)。 服务端会对Date进行时钟偏移检查,最大允许300秒的偏差,超出偏差的请求都将被拒绝。

authorization参数详细生成规则

AICloud控制台,创建平台应用后即可获取接口密钥APIKey 和 APISecret ,快速指引

参数authorization base64编码前(authorization_origin)的格式如下

api_key="$api_key",algorithm="hmac-sha256",headers="host date request-line",signature="$signature"

api_key 是向平台申请的api_key, algorithm 是加密算法,headers 是参与签名的参数。signature 是使用加密算法对参与签名的参数签名后并使用base64编码的字符串

  • signature的生成规则:

signature原始字段由 host,date,request-line三个参数按照格式拼接成 拼接的格式为(\n为换行符,':'后面有一个空格):

host: $host\ndate: $date\n$request-line

例如:

请求的url为 wss://api.xf-yun.com/v1/private/Service_ID
date = Wed, 10 Jul 2019 07:35:43 GMT

那么 signature原始字段则为: signature_origin:

host: api.xf-yun.com
date: Wed, 10 Jul 2019 07:35:43 GMT
GET /v1/private/Service_ID HTTP/1.1
  • 使用hmac-sha256算法结合apiSecret对signature_origin签名,获得签名后的摘要signature_sha
signature_sha=hmac-sha256(signature_origin,$apiSecret)

其中 apiSecret 是在控制台获取的APISecret

  • 使用base64编码对signature_sha进行编码获得最终的signature
signature=base64(signature_sha)

这样就生成了signature参数(注意:signature_sha是未经过任何编码的原始字节)

假设

APISecret = secretxxxxxxxx2df7900c09xxxxxxxx    
date = Wed, 10 Jul 2019 07:35:43 GMT

signature=4VskIJH3URC4/fpbX/FrumOHHuBSk/eGlUv+RkfyG18=

那么生成的base64编码前authorization_origin参数为:

api_key="keyxxxxxxxx8ee279348519exxxxxxxx", algorithm="hmac-sha256", headers="host date request-line", signature="4VskIJH3URC4/fpbX/FrumOHHuBSk/eGlUv+RkfyG18="

注: headers是参与签名的参数,请注意是固定的参数名("host date request-line"),而非这些参数的值。

  • 最后再对authorization_origin进行base64编码获得最终的authorization参数。
authorization = base64(authorization_origin)
示例:
authorization=YXBpX2tleT0ia2V5eHh4eHh4eHg4ZWUyNzkzNDg1MTlleHh4eHh4eHgiLCBhbGdvcml0aG09ImhtYWMtc2hhMjU2IiwgaGVhZGVycz0iaG9zdCBkYXRlIHJlcXVlc3QtbGluZSIsIHNpZ25hdHVyZT0iNFZza0lKSDNVUkM0L2ZwYlgvRnJ1bU9ISHVCU2svZUdsVXYrUmtmeUcxOD0i

如果握手成功,会返回HTTP 101状态码,表示协议升级成功;如果握手失败,则根据不同错误类型返回不同HTTP Code状态码,同时携带错误描述信息,详细错误说明如下:

HTTP Code 说明 错误描述信息 解决方式
401 缺少authorization请求参数 {"message":"Unauthorized"} 按照上面的步骤构建authorization参数,见authorization参数详细生成规则
403 时钟偏移校验失败 {"message":"HMAC signature cannot be verified, a valid date or x-date header is required for HMAC Authentication"} date参数时间戳格式不对或者时间已经过期,与服务端时间戳偏差超过了300s,请检查传入的date参数
401 签名参数解析失败 {"message":"HMAC signature cannot be verified"} authorization参数解析失败,检查authorization参数是否符合 协议要求
401 签名校验失败 {"message":"HMAC signature does not match"} 签名验证失败,可能原因有很多。1. 检查api_key,api_secret 是否正确 2.检查计算签名的参数host,date,request-line是否按照协议要求拼接。 3. 检查signature签名的base64长度是否正常,正常44个字节,如果超出此范围,则可能是参与base64计算的签名信息已经经过编码了,需要使用原始字节进行base64编码。

握手失败返回示例:

HTTP/1.1 401 Forbidden
Date: Thu, 06 Dec 2018 07:55:16 GMT
Content-Length: 116
Content-Type: text/plain; charset=utf-8

{
    "message": "HMAC signature does not match"
}

生成鉴权url示例代码

golang

//@hosturl :  like  wss://api.xf-yun.com/v1/private/Service_ID
//@apikey : apiKey
//@apiSecret : apiSecret
func assembleAuthUrl(hosturl string, apiKey, apiSecret string) string {
    ul, err := url.Parse(hosturl)
    if err != nil {
        fmt.Println(err)
    }
    //签名时间
    date := time.Now().UTC().Format(time.RFC1123)
    //参与签名的字段 host ,date, request-line
    signString := []string{"host: " + ul.Host, "date: " + date, "GET " + ul.Path + " HTTP/1.1"}
    //拼接签名字符串
    sgin := strings.Join(signString, "\n")
    //签名结果
    sha := HmacWithShaTobase64("hmac-sha256", sgin, apiSecret)
    //构建请求参数 此时不需要urlencoding
    authUrl := fmt.Sprintf("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey,
        "hmac-sha256", "host date request-line", sha)
    //将请求参数使用base64编码
    authorization:= base64.StdEncoding.EncodeToString([]byte(authUrl))

    v := url.Values{}
    v.Add("host", ul.Host)
    v.Add("date", date)
    v.Add("authorization", authorization)
    //将编码后的字符串url encode后添加到url后面
    callurl := hosturl + "?" + v.Encode()
    return callurl
}

func HmacWithShaTobase64(algorithm, data, key string) string {
    mac := hmac.New(sha256.New, []byte(key))
    mac.Write([]byte(data))
    encodeData := mac.Sum(nil)
    return base64.StdEncoding.EncodeToString(encodeData)
}

java:

package com.iflytek.webgatews.wsclient;


import okhttp3.*;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 鉴权使用
 * @Date:2019/7/31 15:23
 */
public class AuthUtils {

    /**
     * 生成用于鉴权的URL,websocket 接口
     * @param requestUrl
     * @param apiKey
     * @param apiSecret
     * @return final requestUrl
     */
    public static String assembleRequestUrl(String requestUrl, String apiKey, String apiSecret) {
        URL url = null;
        String  httpRequestUrl = requestUrl.replace("ws://", "http://").replace("wss://","https://" );
        try {
            url = new URL(httpRequestUrl);
            SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            format.setTimeZone(TimeZone.getTimeZone("UTC"));
            String date = format.format(new Date());
//            date = "Thu, 19 Dec 2024 07:47:57 GMT";
            String host = url.getHost();
            StringBuilder builder = new StringBuilder("host: ").append(host).append("\n").//
                    append("date: ").append(date).append("\n").//
                    append("GET ").append(url.getPath()).append(" HTTP/1.1");
            Charset charset = Charset.forName("UTF-8");
            Mac mac = Mac.getInstance("hmacsha256");
            System.out.println(builder.toString());
            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
            mac.init(spec);
            byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
            String sha = Base64.getEncoder().encodeToString(hexDigits);
            String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
            String authBase = Base64.getEncoder().encodeToString(authorization.getBytes(charset));
            return String.format("%s?authorization=%s&host=%s&date=%s", requestUrl, URLEncoder.encode(authBase), URLEncoder.encode(host), URLEncoder.encode(date));

        } catch (Exception e) {
           throw new RuntimeException("assemble requestUrl error:"+e.getMessage());
        }
    }
}

javascript:

function assembleRequestUrl(host,path,apiKey,apiSecret) {
  var url = "wss://"+host+path
  var date = new Date().toGMTString()
  var algorithm = 'hmac-sha256'
  var headers = 'host date request-line'
  var signatureOrigin = `host: ${host}\ndate: ${date}\nGET ${path} HTTP/1.1`
  var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret)
  var signature = CryptoJS.enc.Base64.stringify(signatureSha)
  var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
  var authorization = btoa(authorizationOrigin)
  url = `${url}?authorization=${authorization}&date=${date}&host=${host}`
  return url
}

*python

from datetime import datetime
from wsgiref.handlers import format_date_time
from time import mktime
import hashlib
import base64
import hmac
from urllib.parse import urlencode
import os
import traceback
import json

class AssembleHeaderException(Exception):
    def __init__(self, msg):
        self.message = msg


class Url:
    def __init__(this, host, path, schema):
        this.host = host
        this.path = path
        this.schema = schema
        pass


# calculate sha256 and encode to base64
def sha256base64(data):
    sha256 = hashlib.sha256()
    sha256.update(data)
    digest = base64.b64encode(sha256.digest()).decode(encoding='utf-8')
    return digest


def parse_url(requset_url):
    stidx = requset_url.index("://")
    host = requset_url[stidx + 3:]
    schema = requset_url[:stidx + 3]
    edidx = host.index("/")
    if edidx <= 0:
        raise AssembleHeaderException("invalid request url:" + requset_url)
    path = host[edidx:]
    host = host[:edidx]
    u = Url(host, path, schema)
    return u


# build websocket auth request url
def assemble_ws_auth_url(requset_url, method="GET", api_key="", api_secret=""):
    u = parse_url(requset_url)
    host = u.host
    path = u.path
    now = datetime.now()
    date = format_date_time(mktime(now.timetuple()))
    print(date)
    # date = "Thu, 12 Dec 2019 01:57:27 GMT"
    signature_origin = "host: {}\ndate: {}\n{} {} HTTP/1.1".format(host, date, method, path)
    # print(signature_origin)
    signature_sha = hmac.new(api_secret.encode('utf-8'), signature_origin.encode('utf-8'),
                             digestmod=hashlib.sha256).digest()
    signature_sha = base64.b64encode(signature_sha).decode(encoding='utf-8')
    authorization_origin = "api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"" % (
        api_key, "hmac-sha256", "host date request-line", signature_sha)
    authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8')
    # print(authorization_origin)
    values = {
        "host": host,
        "date": date,
        "authorization": authorization
    }

    return requset_url + "?" + urlencode(values)

results matching ""

    No results matching ""