انتقل إلى المحتوى

مصادقة التطبيق والحساب

تعتمد عملية مصادقة Open API في cTrader على معيار OAuth 2.0.

يسمح هذا الإطار للتطبيقات الخارجية بالحصول على وصول محدود إلى خدمة ما إما نيابة عن مالك المورد، من خلال تنظيم تفاعل الموافقة بين مالك المورد والخدمة، أو من خلال السماح لتطبيق خارجي بالحصول على الوصول نيابة عن نفسه.

تدفق المصادقة

وفقًا لمعيار OAuth 2.0، تتطلب مصادقة الحساب كلاً من رمز التفويض ورمز الوصول.

تعريف الرموز

رمز التفويض هو رمز قصير المدى يتم إصداره لـ cTID فردي. فترة صلاحيته دقيقة واحدة. رمز الوصول هو رمز طويل المدى يسمح للتطبيق بإرسال واستقبال الرسائل من وإلى الواجهة الخلفية لـ cTrader. بعد استلامه، يجب استبدال رمز التفويض سريعًا برمز وصول؛ بعد ذلك، يجب توقيع جميع الرسائل المرسلة إلى الواجهة الخلفية لـ cTrader برمز الوصول المستلم لمصادقة تطبيقك. فترة صلاحية رمز الوصول هي 2,628,000 ثانية (حوالي 30 يومًا). بعد انتهاء صلاحيته، يمكن إنشاء رمز وصول جديد باستخدام رمز التحديث. رمز التحديث ليس له فترة صلاحية.

عادةً، تبدو عملية بدء شخص جديد في استخدام تطبيقك للمرة الأولى كما يلي:

1. يصل مستخدم لديه cTID معين إلى تطبيقك أينما تم نشره؛ يتفاعل المستخدم مع زر إجراء أو ما يعادله.

2. يستخدم التطبيق متصفحًا مدمجًا (أو أي وسيلة مناسبة أخرى) لإعادة توجيه المستخدم إلى عنوان URI محدد حيث سيمنحون التطبيق الأذونات اللازمة.

اكتساب الثقة

قبل إعادة توجيه المستخدم إلى عنوان URI هذا، تأكد من أن المستخدم يثق بتطبيقك ويدرك أنه سيحتاج إلى توفير أذونات إضافية.

3. يتم نقل المستخدم إلى عنوان URL إعادة التوجيه المحدد مسبقًا. يحتوي عنوان URL هذا على رمز الوصول كقيمة لمعلمة الاستعلام code.

4. يتم نقل المستخدم مرة أخرى إلى التطبيق إما من تلقاء نفسه أو تلقائيًا. يتم إخطار التطبيق بقيمة المعلمة code.

5. يرسل التطبيق طلبًا لاستبدال رمز التفويض برمز وصول إلى نقطة نهاية محددة.

6. يتلقى التطبيق استجابة تحتوي على رمز الوصول كقيمة لمفتاح accessToken.

7. يرسل التطبيق رسالة ProtoOAApplicationAuthReq تحتوي على حقول clientId وclientSecret.

8. يرسل التطبيق رسالة ProtoOAGetAccountListByAccessTokenReq تحتوي على حقل accessToken. تحتوي الاستجابة (ProtoOAGetAccountListByAccessTokenRes) على حقل ctidTraderAccountId المتكرر.

9. بعد تلقي الاستجابة، يرسل التطبيق رسالة ProtoOAAccountAuthReq تحتوي على حقلي ctidTraderAccountId وaccessToken.

بعد ذلك، يجب مصادقة المستخدم تحت الحساب الذي يتطابق ctidTraderAccountId الخاص به مع ctidTraderAccountId المقدم خلال الخطوة 8.

يوضح المخطط أدناه كيفية عمل تدفق المصادقة الأساسي من منظور تطبيق Open API الخاص بك.

graph TB
  A(["إعادة توجيه المستخدم إلى <br/> مُعرّف الموارد الموحد (URI) مُحدد"]) ==> B(["استلام رمز <br/> التفويض"]);
  B ==> C(["إرسال طلب للحصول على <br/> رمز الوصول"]);
  C ==> D(["إرسال رسالة <br/> ProtoOAApplicationAuthReq"]);
  D ==> E(["إرسال رسالة <br/> ProtoOAAccountAuthReq"]);

في الأقسام الفرعية أدناه، نشرح الخطوات الرئيسية لتدفق المصادقة بالتفصيل.

إضافة عنوان URI لإعادة التوجيه

كما هو موضح سابقًا، يحتاج تطبيقك إلى الحصول على رمز تفويض بعد إرسال المستخدم إلى عنوان URI معين للإعادة التوجيه. سيتضمن عنوان URI هذا رمز التفويض كقيمة لمعلمة الاستعلام code.

لإضافة عنوان URI جديد لإعادة التوجيه، قم بما يلي:

1. افتح صفحة التطبيقات في بوابة Open API.

2. حدد زر تحرير في الصف الخاص بالتطبيق الذي تريد إضافة عنوان URL إعادة التوجيه إليه.

3. في الشاشة التي تظهر حديثًا، قم بالتمرير لأسفل إلى قسم عناوين URI لإعادة التوجيه.

4. أضف عنوان URL إعادة التوجيه في حقل إدخال نصي فارغ متاح. إذا لم تظهر أي حقول متاحة، حدد زر إضافة عنوان URI لإعادة التوجيه.

5. حدد زر حفظ في أسفل الصفحة لتطبيق تغييراتك.

إدارة عناوين URI لإعادة التوجيه

عنوان URI الأول لإعادة التوجيه مخصص لخدمة Playground التي تتيح لك اختبار تطبيقك قبل منح المستخدمين العاديين حق الوصول إليه. يجب ألا يُستخدم أبدًا لتطبيق إنتاجي. يمكنك إضافة عدد غير محدود من عناوين URI لإعادة التوجيه إذا لزم الأمر.

الحصول على رمز التفويض

للحصول على رمز تفويض لـ cTID محدد، سيحتاج تطبيقك إلى إرسال مستخدم إلى عنوان URI التالي.

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

ملاحظة

في هذه المرحلة، سيحتاج المستخدم إلى السماح لتطبيقك أو خدمتك بالوصول إلى حسابات التداول الخاصة به. نتيجة لذلك، من الضروري أن تزود المستخدم بفهم كامل لما سيتطلبه استخدام تطبيقك أو خدمتك فيما يتعلق بالأذونات وتخزين البيانات ومعالجة البيانات.

يحتوي عنوان URI هذا على معلمات الاستعلام التالية.

المعلمة مطلوب؟ التعريف
client_id نعم المعرف الفريد لتطبيق Open API الخاص بك.
redirect_uri نعم عنوان URI إعادة التوجيه صالح محدد في إعدادات تطبيقك.
scope نعم نطاق الأذونات التي ترغب في منحها لتطبيقك. يتم قبول القيم التالية:
accounts. يتم منح حق الوصول للعرض فقط. سيتمكن تطبيقك من الوصول إلى معلومات الحساب والإحصائيات؛ لن يكون من الممكن تنفيذ عمليات التداول.
trading. يتم منح وصول كامل إلى معلومات الحساب والإحصائيات وكذلك جميع عمليات التداول المسموح بها.
product لا إذا تم تحديد هذا المعلم وتعيينه على web، فإن شاشة التفويض تفتقر إلى الرأس والتذييل، مما يجعلها تبدو أفضل على الأجهزة المحمولة. في حين أن المعلم اختياري، نوصي بتعيينه على web.

لعرض client_id الخاص بك، انتقل إلى صفحة التطبيقات وحدد زر عرض في عمود بيانات الاعتماد.

بعد إرسال المستخدم إلى عنوان URI أعلاه (وطالما أن كلا المعلمتين صالحتان)، يجب أن يروا شاشة تسجيل الدخول/التسجيل تطلب منهم التفويض بموجب cTID الخاص بهم. بعد ذلك، سيتم عرض مربع حوار للمستخدم حيث سيتمكن من السماح للتطبيق بالوصول إلى حساب واحد أو أكثر مرتبط بـ cTID الخاص به.

عندما يحدد المستخدم زر السماح بالوصول، ستتم إعادة توجيهه إلى redirect_uri الذي حددته في الأصل. كما هو موضح في المثال أدناه، سيتم إضافة رمز التفويض إلى عنوان URI هذا كمعلمة استعلام.

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

في هذه المرحلة، سيحتاج تطبيقك إلى الوصول إلى قيمة معلمة code وتخزينها. يجب استبدالها سريعًا برمز وصول قبل انتهاء صلاحية رمز التفويض.

حسابات إضافية

إذا قام المستخدم بإنشاء حسابات إضافية بعد إكمال الإجراءات الموضحة أعلاه، فلن يتم تفويض هذه الحسابات داخل التطبيق. بدلاً من ذلك، سيحتاج المستخدم إلى إعادة توجيهه مرة أخرى إلى عنوان URL المقدم أعلاه حتى يتمكن من منح التطبيق حق الوصول إلى أي حسابات إضافية قام بإنشائها منذ آخر تسجيل دخول.

المصادقة عبر Google

إذا تم فتح عنوان URI أعلاه عبر WebView واختار المستخدم Google لتسجيل الدخول، فسيعرض Google صفحة الوصول محظور، مما يمنع المستخدم من المتابعة.

لمنع هذا، تأكد من أن توقيع user-agent للجهاز الذي يفتح الصفحة يبدو كما يلي.

'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'

الحصول على رمز وصول

للحصول على رمز وصول، قم بتنفيذ استدعاء REST API التالي.

عنوان URL نسبي

عنوان URL للطلب نسبي إلى https://openapi.ctrader.com.

الطريقة عنوان URL
GET apps/token

يتضمن هذا الطلب معلمات الاستعلام التالية.

المعلمة مطلوب؟ التعريف
grant_type نعم نوع الرمز المرسل إلى نقطة النهاية هذه. يتم قبول القيم التالية.
authorization_code. يتم إرسال رمز تفويض إلى نقطة النهاية لاستبداله برمز وصول.
refresh_token. يتم إرسال رمز تحديث إلى نقطة النهاية لتحديث رمز وصول موجود.
code لا الرمز المرسل إلى نقطة النهاية. هذا المعلم إلزامي إذا كان grant_type=authorization_code.
redirect_uri لا عنوان URI إعادة التوجيه صالح محدد في إعدادات تطبيقك. هذا المعلم إلزامي إذا كان grant_type=authorization_code.
client_id نعم المعرف الفريد لتطبيق Open API الخاص بك.
client_secret نعم المفتاح السري المخصص لتطبيق Open API الخاص بك.

يمكن العثور على مثال الطلب أدناه.

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'

لعرض client_secret الخاص بك، عُد إلى صفحة التطبيقات وحدد زر عرض في عمود بيانات الاعتماد.

عند نجاح الطلب، يجب أن تتلقى استجابة تحتوي على المفاتيح التالية.

المفتاح نوع القيمة التعريف
"accessToken" سلسلة رمز الوصول الذي سيستخدمه تطبيقك لمصادقة الرسائل المرسلة إلى Open API الخاص بـ cTrader.
"tokenType" سلسلة نوع رمز الوصول (يجب أن تكون bearer"" قيمة هذا المفتاح حيث يتم استخدام معيار REST لإجراء الطلب).
"expiresIn" integer عدد الثواني التي يجب أن تمر قبل انتهاء صلاحية رمز الوصول (بشكل افتراضي، تساوي قيمة هذا المفتاح 2628000).
"refreshToken" سلسلة رمز التحديث الذي يجب استخدامه لتجديد رمز الوصول بمجرد انتهاء صلاحيته. لا يوجد وقت انتهاء صلاحية لرمز التحديث نفسه.
"errorCode" string/null رمز الخطأ الذي يصف سبب فشل الطلب. بالنسبة للطلب الناجح، يجب أن تكون قيمة هذا المفتاح null.
"description" string/null وصف الخطأ الذي حدث أثناء الطلب غير الناجح. بالنسبة للطلب الناجح، يجب أن تكون قيمة هذا المفتاح null.

لمثال على استجابة ناجحة، انظر المقتطف أدناه.

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

إرسال رسائل ProtoBuf المطلوبة

بعد استلام رمز وصول صالح، سيحتاج تطبيقك إلى إرسال رسائل ProtoOAApplicationAuthReq و ProtoOAGetAccountListByAccessTokenReq و ProtoOAAccountAuthReq. يمكن القيام بذلك على النحو التالي.

 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)

تحديث رمز الوصول

بعد انتهاء صلاحية رمز الوصول، سيتعين عليك تجديده باستخدام refreshToken الذي تلقيته سابقًا. يمكنك تنفيذ هذا الإجراء عبر طريقتين مختلفتين.

إرسال طلب HTTP

للحصول على رمز وصول جديد (وبالتالي رمز تحديث جديد)، يمكنك تنفيذ نفس طلب HTTP المذكور أعلاه. كما هو موضح في المثال أدناه، سيتعين عليك تعيين معامل الاستعلام grant_type إلى 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'

ستتلقى استجابة تحتوي على القيم الجديدة لمفاتيح accessToken و refreshToken. يمكنك استخدام هذه القيم الجديدة بأمان بينما يتم إبطال القيم القديمة للمفاتيح نفسها تلقائيًا.

إرسال رسالة Protobuf

بدلاً من ذلك، يمكنك إرسال ProtoOARefreshTokenReq وتلقي رسالة ProtoOARefreshTokenRes التي تحتوي على رموز صالحة جديدة.

 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")

استخدام Playground

يوفر Playground وسيلة سريعة للحصول على رمز وصول لـ cTID الخاص بك، مما يتيح لك تطوير واختبار تطبيقك بسرعة وسهولة قبل توزيعه بين جمهوره المستهدف.

للوصول إلى Playground، انتقل إلى صفحة Applications وحدد زر Playground. في النافذة التي تظهر حديثًا، حدد نطاق التطبيق وانقر على زر Get token.

بعد ذلك، يجب أن ترى الصفحة التالية.

يمكنك استخدام رمز الوصول ورمز التحديث لإرسال رسائل إلى Open API أثناء المصادقة تحت cTID الخاص بك.