Przejdź do treści

Uwierzytelnianie aplikacji i konta

Proces uwierzytelniania cTrader Open API opiera się na standardzie OAuth 2.0.

Ta struktura umożliwia aplikacjom firm trzecich uzyskanie ograniczonego dostępu do usługi w imieniu właściciela zasobu, poprzez zorganizowanie interakcji zatwierdzającej między właścicielem zasobu a usługą, lub poprzez umożliwienie aplikacji firm trzecich uzyskania dostępu we własnym imieniu.

Przepływ uwierzytelniania

Zgodnie ze standardem OAuth 2.0, uwierzytelnianie konta wymaga zarówno kodu autoryzacyjnego, jak i tokenu dostępu.

Zdefiniuj tokeny

Kod autoryzacyjny to krótkoterminowy token, który jest wydawany dla indywidualnego cTID. Jego okres ważności wynosi jedną minutę. Token dostępu to długoterminowy token, który umożliwia aplikacji wysyłanie i odbieranie komunikatów do i z backendu cTrader. Po jego otrzymaniu kod autoryzacyjny musi zostać szybko wymieniony na token dostępu; następnie wszystkie komunikaty wysyłane do backendu cTrader muszą być podpisane otrzymanym tokenem dostępu w celu uwierzytelnienia aplikacji. Okres ważności tokenu dostępu wynosi 2 628 000 sekund (około 30 dni). Po jego wygaśnięciu nowy token dostępu można wygenerować za pomocą tokenu odświeżania. Token odświeżania nie ma okresu ważności.

Zazwyczaj proces rozpoczęcia korzystania z aplikacji przez nową osobę wygląda następująco:

1. Użytkownik z określonym cTID uzyskuje dostęp do aplikacji w miejscu jej wdrożenia; użytkownik wchodzi w interakcję z przyciskiem akcji lub równoważnym elementem.

2. Aplikacja używa wbudowanej przeglądarki (lub innego odpowiedniego środka), aby przekierować użytkownika do określonego URI, gdzie udzieli aplikacji niezbędnych uprawnień.

Zdobądź zaufanie

Przed przekierowaniem użytkownika do tego URI upewnij się, że użytkownik ufa aplikacji i jest świadomy faktu, że będzie musiał udzielić dodatkowych uprawnień.

3. Użytkownik jest przekierowywany do predefiniowanego adresu URL przekierowania. Ten adres URL zawiera token dostępu jako wartość parametru zapytania code.

4. Użytkownik jest przekierowywany z powrotem do aplikacji z własnej woli lub automatycznie. Aplikacja zostaje poinformowana o wartości parametru code.

5. Aplikacja wysyła żądanie wymiany kodu autoryzacyjnego na token dostępu do określonego punktu końcowego.

6. Aplikacja otrzymuje odpowiedź zawierającą token dostępu jako wartość klucza accessToken.

7. Aplikacja wysyła komunikat ProtoOAApplicationAuthReq zawierający pola clientId i clientSecret.

8. Aplikacja wysyła komunikat ProtoOAGetAccountListByAccessTokenReq zawierający pole accessToken. Odpowiedź (ProtoOAGetAccountListByAccessTokenRes) zawiera powtarzane pole ctidTraderAccountId.

9. Po otrzymaniu odpowiedzi aplikacja wysyła komunikat ProtoOAAccountAuthReq zawierający pola ctidTraderAccountId i accessToken.

Następnie użytkownik powinien zostać uwierzytelniony na koncie, którego ctidTraderAccountId odpowiada ctidTraderAccountId podanemu podczas kroku 8.

Poniższy diagram wyjaśnia, jak działa podstawowy przepływ uwierzytelniania z perspektywy aplikacji Open API.

graph TB
  A([Przekieruj użytkownika <br/> na określony URI]) ==> B([Odbierz kod <br/> autoryzacyjny]);
  B ==> C([Wyślij żądanie <br/> uzyskania <br/> kodu dostępu]);
  C ==> D([Wyślij <br/> wiadomość <br/> ProOAApplicationAuthReq]);
  D ==> E([Wyślij <br/> wiadomość <br/> ProtoOAAccountAuthReq]);

W poniższych podsekcjach szczegółowo wyjaśniamy kluczowe etapy przepływu uwierzytelniania.

Dodaj URI przekierowania

Jak pokazano wcześniej, aplikacja musi uzyskać kod autoryzacyjny po wysłaniu użytkownika do określonego URI przekierowania. Ten URI będzie zawierał kod autoryzacyjny jako wartość parametru zapytania code.

Aby dodać nowy URI przekierowania, wykonaj następujące czynności:

1. Otwórz stronę Aplikacje w portalu Open API.

2. Wybierz przycisk Edytuj w wierszu z aplikacją, do której chcesz dodać adres URL przekierowania.

3. Na nowo wyświetlonym ekranie przewiń w dół do sekcji URI przekierowania.

4. Dodaj adres URL przekierowania w dostępnym pustym polu wprowadzania tekstu. Jeśli nie są wyświetlane żadne dostępne pola, wybierz przycisk Dodaj URI przekierowania.

5. Wybierz przycisk Zapisz u dołu strony, aby zastosować zmiany.

Zarządzaj URI przekierowania

Pierwsze URI przekierowania jest przeznaczone dla usługi Playground, która umożliwia przetestowanie aplikacji przed udostępnieniem jej zwykłym użytkownikom. Nigdy nie może być używane w aplikacji produkcyjnej. W razie potrzeby możesz dodać nieograniczoną liczbę URI przekierowania.

Uzyskaj kod autoryzacyjny

Aby otrzymać kod autoryzacyjny dla określonego cTID, Twoja aplikacja będzie musiała wysłać użytkownika do następującego URI.

https://id.ctrader.com/my/settings/openapi/grantingaccess/?client_id={clientId}&redirect_uri={your_redirectURI}&scope={scope}&product=web

Uwaga

Na tym etapie użytkownik będzie musiał zezwolić Twojej aplikacji lub usłudze na dostęp do swoich kont handlowych. W związku z tym konieczne jest zapewnienie użytkownikowi pełnego zrozumienia, jakie uprawnienia, przechowywanie danych i przetwarzanie danych będzie wymagać korzystanie z Twojej aplikacji lub usługi.

Ten URI ma następujące parametry zapytania.

Parametr Wymagane? Definicja
client_id Tak Unikalny identyfikator Twojej aplikacji otwartego API.
redirect_uri Tak Prawidłowy URI przekierowania określony w ustawieniach Twojej aplikacji.
scope Tak Zakres uprawnień, które chcesz przyznać swojej aplikacji. Akceptowane są następujące wartości:
accounts. Przyznawany jest dostęp tylko do odczytu. Twoja aplikacja będzie mogła uzyskać dostęp do informacji o koncie i statystyk; wykonywanie operacji handlowych będzie niemożliwe.
trading. Przyznawany jest pełny dostęp do informacji o koncie i statystyk, a także wszystkich dozwolonych operacji handlowych.
product Nie Jeśli ten parametr jest określony i ustawiony na web, ekran autoryzacji nie zawiera nagłówka i stopki, co sprawia, że wygląda lepiej na urządzeniach mobilnych. Chociaż parametr jest opcjonalny, zalecamy ustawienie go na web.

Aby wyświetlić swój client_id, przejdź do strony Aplikacje i wybierz przycisk Wyświetl w kolumnie Poświadczenia.

Po wysłaniu użytkownika do powyższego URI (i o ile oba parametry są prawidłowe), powinien zobaczyć ekran logowania/rejestracji z prośbą o autoryzację przy użyciu swojego cTID. Następnie użytkownikowi zostanie wyświetlone okno dialogowe, w którym będzie mógł zezwolić aplikacji na uzyskanie dostępu do jednego lub więcej kont powiązanych z jego cTID.

Gdy użytkownik wybierze przycisk Zezwól na dostęp, zostanie przekierowany do redirect_uri, który pierwotnie określiłeś. Jak pokazano w poniższym przykładzie, kod autoryzacyjny zostanie dodany do tego URI jako parametr zapytania.

https://my-redirect-uri.com/?code=123ASDASffdg_as234_GCllkoq14adRB7_tvN

W tym momencie Twoja aplikacja będzie musiała uzyskać dostęp i zapisać wartość parametru code. Musi on zostać szybko wymieniony na token dostępu, zanim kod autoryzacyjny wygaśnie.

Dodatkowe konta

Jeśli użytkownik utworzy dodatkowe konta po wykonaniu czynności opisanych powyżej, te konta nie będą autoryzowane w aplikacji. Zamiast tego użytkownik będzie musiał zostać przekierowany z powrotem do adresu URL podanego powyżej, aby mógł udzielić aplikacji dostępu do wszelkich dodatkowych kont, które utworzył od ostatniego logowania.

Uwierzytelnianie przez Google

Jeśli powyższy URI zostanie otwarty przez WebView, a użytkownik wybierze Google do logowania, Google wyświetli stronę Dostęp zablokowany, uniemożliwiając użytkownikowi dalsze działanie.

Aby temu zapobiec, upewnij się, że podpis user-agent urządzenia otwierającego stronę wygląda następująco.

'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'

Uzyskaj token dostępu

Aby uzyskać token dostępu, wykonaj następujące wywołanie REST API.

Względny adres URL

Adres URL żądania jest względny w stosunku do https://openapi.ctrader.com.

Metoda URL
GET apps/token

To żądanie zawiera następujące parametry zapytania.

Parametr Wymagane? Definicja
grant_type Tak Typ tokenu wysłanego do tego punktu końcowego. Akceptowane są następujące wartości.
authorization_code. Kod autoryzacyjny jest wysyłany do punktu końcowego w celu wymiany go na token dostępu.
refresh_token. Token odświeżania jest wysyłany do punktu końcowego w celu odświeżenia istniejącego tokenu dostępu.
code Nie Token wysłany do punktu końcowego. Ten parametr jest obowiązkowy, jeśli grant_type=authorization_code.
redirect_uri Nie Prawidłowy URI przekierowania określony w ustawieniach Twojej aplikacji. Ten parametr jest obowiązkowy, jeśli grant_type=authorization_code.
client_id Tak Unikalny identyfikator Twojej aplikacji otwartego API.
client_secret Tak Tajny klucz przypisany do Twojej aplikacji otwartego API.

Przykład żądania można znaleźć poniżej.

curl -X GET 'https://openapi.ctrader.com/apps/token?grant_type=authorization_code&code=0ssdgds98as9_QSF56FVC_22dfdf&redirect_uri=https://spotware.com&client_id=5430012&client_secret=012sds23dlkjQsd' -H 'Accept: application/json' -H 'Content-Type: application/json'

Aby wyświetlić swój client_secret, wróć do strony Aplikacje i wybierz przycisk Wyświetl w kolumnie Poświadczenia.

Po pomyślnym żądaniu powinieneś otrzymać odpowiedź z następującymi kluczami.

Klucz Typ wartości Definicja
"accessToken" string Token dostępu, którego Twoja aplikacja będzie używać do uwierzytelniania wiadomości wysyłanych do cTrader Open API.
"tokenType" string Typ tokenu dostępu (wartością tego klucza powinien być "bearer", ponieważ do wykonania żądania używany jest standard REST).
"expiresIn" integer Liczba sekund, które muszą upłynąć, zanim token dostępu wygaśnie (domyślnie wartość tego klucza wynosi 2628000).
"refreshToken" string Token odświeżania, który musi zostać użyty do odnowienia tokenu dostępu po jego wygaśnięciu. Sam token odświeżania nie ma czasu wygaśnięcia.
"errorCode" string/null Kod błędu opisujący, dlaczego żądanie zakończyło się niepowodzeniem. W przypadku pomyślnego żądania wartość tego klucza powinna wynosić null.
"description" string/null Opis błędu, który wystąpił podczas nieudanego żądania. W przypadku pomyślnego żądania wartość tego klucza powinna wynosić null.

Przykład pomyślnej odpowiedzi można znaleźć w poniższym fragmencie.

{
    "accessToken":"mos8Bw3D4EG0fRPd4Eqq0JxaFT4zjd8e4YijNezh_ag",
    "tokenType":"bearer",
    "expiresIn":2628000,
    "refreshToken":"VCuafFhy81AFZjsWkbuEzdOhhRj5YTWz8fWUwHam7KM",
    "errorCode":null,
    "description":null,
}

Wyślij wymagane komunikaty ProtoBuf

Po otrzymaniu prawidłowego kodu dostępu Twoja aplikacja będzie musiała wysłać komunikaty ProtoOAApplicationAuthReq, ProtoOAGetAccountListByAccessTokenReq i ProtoOAAccountAuthReq. Można to zrobić w następujący sposób.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
private static RepeatedField<ProtoOACtidTraderAccount> _ctidTraderAccounts;

List<IDisposable> _disposables = new();
_disposables.Add(_client.OfType<ProtoOAGetAccountListByAccessTokenRes>().Subscribe(OnAccountIdReceived));

private static void OnAccountIdReceived(ProtoOAGetAccountListByAccessTokenRes response)
{

    Console.WriteLine($"\nMessage Received:\n{response}");

    _ctidTraderAccounts = response.CtidTraderAccount;

    var accountAuthReq = new ProtoOAAccountAuthReq
    {
        CtidTraderAccountId = (long)_ctidTraderAccounts[0].CtidTraderAccountId,
        AccessToken = _token.AccessToken,
    };

    _client.SendMessage(accountAuthReq);

}

var _client = new OpenClient(host, ApiInfo.Port, TimeSpan.FromSeconds(10), useWebSocket: false);
var applicationAuthReq = new ProtoOAApplicationAuthReq
{
    ClientId = {your_client_id}, // Add your client ID here
    ClientSecret = {your_app_secret}, // Add your app secret here
};
await _client.SendMessage(applicationAuthReq);
await Task.Delay(5000);
var getAccountListByAccessToken = new ProtoOAGetAccountListByAccessTokenReq 
{
    AccessToken = {access_token} // Add your access token here
}
var accountAuthReq = new ProtoOAAccountAuthReq 
{
    ctidTraderAccountId = {account_id}, // Add the ctidTraderAccountId of the account you want to authorize here
    AccessToken = {access_token} // Add your access token here
};
await _client.SendMessage(accountAuthReq);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
currentAccountId = None
client = Client(EndPoints.PROTOBUF_LIVE_HOST if hostType.lower() == "live" else EndPoints.PROTOBUF_DEMO_HOST, EndPoints.PROTOBUF_PORT, TcpProtocol)

def connected(client): # Callback for client connection
    print("\nConnected")
    request = ProtoOAApplicationAuthReq()
    request.clientId = appClientId
    request.clientSecret = appClientSecret
    deferred = client.send(request)



def disconnected(client, reason): # Callback for client disconnection
    print("\nDisconnected: ", reason)

def onMessageReceived(client, message): # Callback for receiving all messages
    global currentAccountId
    if message.payloadType in [ProtoOASubscribeSpotsRes().payloadType, ProtoOAAccountLogoutRes().payloadType, ProtoHeartbeatEvent().payloadType]:
        return
    elif message.payloadType == ProtoOAApplicationAuthRes().payloadType:
        print("API Application authorized\n")
        if currentAccountId is not None:
            sendProtoOAAccountAuthReq()
            return
        accountListReq = ProtoOAGetAccountListByAccessTokenReq()
        accountListReq.accessToken = accessToken
        deferred = client.send(accountListReq)
    elif message.payloadType == ProtoOAGetAccountListByAccessTokenRes().payloadType:
        protoOAGetAccountListByAccessTokenRes = Protobuf.extract(message)
        currentAccountId = int(protoOAGetAccountListByAccessTokenRes.ctidTraderAccount[0].ctidTraderAccountId)
        accountAuthReq = ProtoOAAccountAuthReq()
        accountAuthReq.ctidTraderAccountId = currentAccountId
        accountAuthReq.accessToken = accessToken
        deferred = client.send(accountAuthReq)
    elif message.payloadType == ProtoOAAccountAuthRes().payloadType:
        protoOAAccountAuthRes = Protobuf.extract(message)
        print(f"Account {protoOAAccountAuthRes.ctidTraderAccountId} has been authorized\n")
        print("This acccount will be used for all future requests\n")
    else:
        print("Message received: \n", Protobuf.extract(message))
    reactor.callLater(3, callable=executeUserCommand)

def onError(failure): # Call back for errors
    print("Message Error: ", failure)
    reactor.callLater(3, callable=executeUserCommand)

Odśwież token dostępu

Po wygaśnięciu tokena dostępu będziesz musiał(-a) go odnowić za pomocą refreshToken, który otrzymałeś(-aś) wcześniej. Możesz wykonać tę czynność za pomocą dwóch różnych metod.

Wyślij żądanie HTTP

Aby uzyskać nowy token dostępu (a następnie nowy token odświeżania), możesz wykonać to samo żądanie HTTP omówione powyżej. Jak pokazano w poniższym przykładzie, musisz ustawić parametr zapytania grant_type na refresh_token.

curl -X POST 'https://openapi.ctrader.com/apps/token?grant_type=refresh_token&refresh_token=asdXCVCVAS_218kjashf_asdasd2ASD_223x&client_id=5430012&client_secret=012sds23dlkjQsd' -H 'Accept: application/json' -H 'Content-Type: application/json'

Otrzymasz odpowiedź zawierającą nowe wartości kluczy accessToken i refreshToken. Możesz bezpiecznie używać tych nowych wartości, podczas gdy stare wartości tych samych kluczy są automatycznie unieważniane.

Wyślij komunikat Protobuf

Alternatywnie możesz wysłać ProtoOARefreshTokenReq i otrzymać komunikat ProtoOARefreshTokenRes zawierający nowe prawidłowe tokeny.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
_disposables.Add(_client.OfType<ProtoOARefreshTokenRes>().Subscribe(OnRefreshTokenResponse));
private static void OnRefreshTokenResponse(ProtoOARefreshTokenRes response) 
{
    _token = new Token 
    {
        AccessToken = response.AccessToken,
        RefreshToken = response.RefreshToken,
        ExpiresIn = DateTimeOffset.FromUnixTimeMilliseconds(response.ExpiresIn),
        TokenType = response.TokenType,
    }
}
var refreshTokenReq = new ProtoOARefreshTokenReq
    {
        refreshToken = {your_refresh_token}, // Add your refresh token here
    };
await _client.SendMessage(applicationAuthReq);
1
newToken = auth.refreshToken("refresh_Token")

Użyj Playground

Playground zapewnia szybki sposób uzyskania tokena dostępu dla Twojego własnego cTID, umożliwiając szybkie i łatwe opracowanie i przetestowanie aplikacji przed jej dystrybucją wśród docelowych odbiorców.

Aby uzyskać dostęp do Playground, przejdź do strony Applications i wybierz przycisk Playground. W nowo otwartym oknie wybierz zakres aplikacji i kliknij przycisk Get token.

Następnie powinieneś(-naś) zobaczyć następującą stronę.

Możesz użyć tokena dostępu i tokena odświeżania do wysyłania komunikatów do API podczas uwierzytelniania pod swoim własnym cTID.