# Доступ

# Прежде чем получить доступ

  • Убедитесь, что соответствующие права для доступа через API включены. Неавторизованные попытки доступа через API могут привести к приостановке действия учетной записи.
  • Убедитесь, что ограничение на частоту подключений настроено правильно. Превышение ограничения приведет к временной приостановке.
  • Примите надлежащие меры по предотвращению повторного входа, поскольку проблемы с сетью могут привести к множественным вызовам, что в свою очередь приведет к дублирующимся сообщениям вызовов, отправляемым получающим доступ, что может негативно сказаться на пользователях.
  • Выполняйте проверку отправляемых данных, чтобы избежать их фальсификации или потери.
  • Пользователи могут получить только информацию о водителях в своем таксопарке.

# Запрос доступа к соответствующим ключам

Для запроса ключей доступа и ключей дешифрации перейдите на веб-сайт fleet > «Учетная запись» > «open api». Ключи будут предоставлены после того, как ваш запрос будет одобрен проверяющим.

# Порталы API

Производственная среда:

https://open-jelly-ru.didiglobal.com/ 
1

Среда песочницы:

https://open-jelly-ru-sim.didiglobal.com
1

# Служебные запросы

Производственная среда:

// Управление балансом водителей
curl -X POST 
-H "Content-Type: application/json" 
-H "Authorization: bearer {cid}|{access_token}"
-d 'json {
    "fleet_id": 10000000000000,
    "driver_id": 50000000000000,
    "location_country": "RU",
    "lang": "ru-RU"
}' 
'https://open-jelly-ru.didiglobal.com/biz/fleet/open-api/drivers/getBalance'
1
2
3
4
5
6
7
8
9
10
11

Среда песочницы:

// Управление балансом водителей
curl -X POST 
-H "Content-Type: application/json" 
-H "Authorization: bearer {cid}|{access_token}"
-d 'json {
    "fleet_id": 10000000000000,
    "driver_id": 50000000000000,
    "location_country": "RU",
    "lang": "ru-RU"
}' 
'https://open-jelly-ru-sim.didiglobal.com/biz/fleet/open-api/drivers/getBalance'
1
2
3
4
5
6
7
8
9
10
11

Примечание

Для запроса к служебному API требуется domain + "/biz" + api_url Не забудьте "/biz"

# Проверка безопасности

Метод: POST

URL: /oauth/token

Функция: Oauth2.0-проверка

Запрашиваемые параметры:

Название параметра Тип Описание
grant_type string Режим запроса. Поддерживаются только два режима.. i.Режим клиента: client_credentials ii.Обновитьtoken: refresh_token
scope string Список запрашиваемых прав доступа.
_ string Текущее время, формат — «2006-01-02T15:04:05-0700», 10 мин. Не проверяется в тестовой среде
nostr string Случайная строка, 6 симв., сочетание цифр и букв (без учета регистра)
refresh_token string Поле refresh_token появляется при запросе token (Требуется для обновления)

Диапазоны значений Scope

Значение Scope Описание
fleet fleet функции

token запроса:

curl -X POST -H "Content-Type: application/json"
-H "Authorization: Bearer {cid}|{sign}"
-d '{"grant_type":"client_credentials","_":"2016-07-01T10:00:00+0800""nostr":"123abc"}'
'https://open-jelly-ru.didiglobal.com/oauth/token'
1
2
3
4

token обновления:

curl -X POST -H "Authorization: Bearer {cid}|{sign}" 
-H "Content-Type: application/json" 
-d '{"grant_type":"refresh_token","refresh_token":"43713d0303-49c60a08fe-835c9fc1fe","_":"2016-07-01T11:00:00+0800","nostr":"123abc"}' 
'https://open-jelly-ru.didiglobal.com/oauth/token'
1
2
3
4

Нормальный ответ:

Название параметра Тип Описание
access_token string Токен доступа token, Должен быть предоставлен header при запросе к другим API. Сразу несколько token могут одновременно быть активны на платформе
refresh_token string token обновления, который используется, когда истекает срок действия access_token. Этот token может быть действителен только один раз. После обновления будет назначен новый refresh_token. У токена нет фиксированной даты окончания срока действия
expires_in_second int access_token — срок действия (секунды).
token_type string token — тип,bearer/mac. Поддерживается только тип bear.
scope string token Уровень доступа токена (тот же, что и запрашиваемый уровень)

Примечание

Ограничение на частоту запросов token: платформа <= 10 раз/день; обновление <= 10 раз/день. После превышения ограничения учетная запись будет приостановлена на 24 ч.

Возвращенный результат:

Статус http

  • 200 обозначает, что запрос действителен
  • Не 200 указывает на ошибку запроса

HTTP/1.1 200 OK

Content-Type: application/json;charset=UTF-8

{
"access_token": "didiCB5DEFD8086CE8EAC49CFDCFFA3BF94E66BFC287113521F868B9257E8782D0DB978B81A04133BA5968D9B15B6A4655A9B3B8E7E856ED69BC1FF5848DC784C5080523D74F1AA6B2AC310219BAD3CDE24DF60E61A83B67565B0FC63DE417858FF4",
"refresh_token": "bd01a0d243-e4a056f463-138c7a00fd",
"expires_in_second": 259200,
"token_type": "bearer",
"scope": "calling_car"
}
1
2
3
4
5
6
7

Описание:

  1. Формат данных запроса должен быть json
  2. header должен содержать id и подпись получающего доступ. Authorization: bearer {cid}|{sign}. bearer представляет собой тип token. cid — назначенный id получающего доступ, связанный с подписью sign через "|"
  3. Алгоритм подписи

Версия php

function generalCreateSign( $aData = array(), $sKey = '' )
{
    if ( empty( $aData ) || ! is_string( $sKey ) ) { //Данные подписи не могут быть пустыми, и key должен быть строкой
        return FALSE;
    }

    ksort( $aData ); //Данные подписи упорядочиваются по значению ключа в алфавитном порядке
    $str = '';
    foreach ( $aData as $k => $v ) {
        if ( empty( $v ) && $v !== 0 ) { //Пустое значение ключа не используется в подписи
            continue;
        }

        if ( is_array( $v ) ) {
            $v = json_encode( $v );
        }
        $str .= trim( $k ) . '=' . trim( $v ) . '&'; //Ключ1=Значение1&Ключ2=Значение2...
    }
    $str = trim( $str, '&' ); //Удалить символы & с обоих концов строки
    return md5( md5( $str ) . $sKey ); //2 раза md5, key — это подпись, назначенная принадлежащему получателю key
}

Версия golang

func generalCreateSign(req GetTokenReq, clientSecret string) string {
	reqData := map[string]string{}
	keys := []string{}

	t := reflect.TypeOf(req)
	v := reflect.ValueOf(req)
	for i := 0; i < t.NumField(); i++ {
		tag := t.Field(i).Tag.Get("json")
		value := v.Field(i).String() // req Все поля типа string 
		reqData[tag] = value
		keys = append(keys, tag)
	}

	// Упорядочить в алфавитном порядке
	sort.Strings(keys)

	sign := ""
	for _, k := range keys {
		if reqData[k] == "" {
			continue
		}

		// k1=v1&k2=v2...
		sign += strings.TrimSpace(k) + "=" + strings.TrimSpace(reqData[k]) + "&"
	}
	sign = strings.Trim(sign, "&")

	withSecret := fmt.Sprintf("%x", md5.Sum([]byte(sign))) + clientSecret
	return fmt.Sprintf("%x", md5.Sum([]byte(withSecret)))
}

Версия c#

public static string GenerateMD5(string txt)
{
	byte[] buffer = Encoding.Default.GetBytes(txt);
	byte[] newBuffer = MD5.Create().ComputeHash(buffer);
	StringBuilder sb = new StringBuilder();
	for (int i = 0; i < newBuffer.Length; i++)
	{
		sb.Append(newBuffer[i].ToString("x2"));
	}
	return sb.ToString();
}

public static string GeneralCreateSign(IDictionary parameters, string secret)
{
	IDictionary sortedParams = new SortedDictionary(parameters);
	IEnumerator> iterator = sortedParams.GetEnumerator();

	StringBuilder strBuilder = new StringBuilder();
	while (iterator.MoveNext())
	{
		string key = iterator.Current.Key;
		string value = iterator.Current.Value;
		if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
		{
			strBuilder.Append(key).Append("=").Append(value).Append("&");
		}
	}

	string finalString = strBuilder.ToString().Trim('&');

	string result = GenerateMD5(GenerateMD5(finalString) + secret);

	return result;
}

Версия java

public static String Md5(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    byte s[] = MessageDigest.getInstance("md5").digest(str.getBytes("UTF8"));
    String Md5String = "";
    for (int i = 0; i < s.length; i++) {
        Md5String += Integer.toHexString((0x000000FF & s[i]) | 0xFFFFFF00).substring(6);
    }
    return Md5String;

}

public static Map sortMapByKey(Map map) {
    if (map == null || map.isEmpty()) {
        return null;
    }
    Map sortMap = new TreeMap(new Comparator() {
        public int compare(String obj1, String obj2) {
            return obj1.compareTo(obj2);//Упорядочить по возрастанию
        }
    });
    sortMap.putAll(map);
    return sortMap;
}

public static String CreateSign(Map params, String key) throws Exception {

    if (key.isEmpty() || params.isEmpty()){
        throw new Exception("sign key is empty or param is empty");
    }
    // Упорядочить
    params = sortMapByKey(params);
    Iterator> it = params.entrySet().iterator();

    String sign = "";
    while (it.hasNext()){
        Map.Entry entry =  it.next();
        String k = entry.getKey();
        String v = entry.getValue();

        if (!v.isEmpty()){
            sign+=k.trim()+"="+v.trim()+"&";
        }
    }
    // Убрать конечные &
    sign = sign.substring(0,sign.length()-1);
    // md5
    return Md5(Md5(sign)+key) ;
}