EAの認証システムブラックリスト方式
EAの認証システム:ブラックリスト方式の利点と活用法
エキスパートアドバイザー(EA)の配布と管理において、ホワイトリスト形式の認証システムが一般的です。しかし、ブラックリスト方式を採用することで、柔軟性が高まり、特に「IB(Introducing Broker)紐付け」のような特定の条件を満たしたユーザーに対して機能をアップグレードさせる場合に効果的です。
ホワイトリスト方式とブラックリスト方式の違い
伝統的なホワイトリスト方式では、事前に認証されたユーザーのみがEAを使用できます。これに対して、ブラックリスト方式では基本的に全員がEAを利用できるが、特定の条件を満たさないユーザー(例えばIBに紐づいていないユーザー)を後から制限する形をとります。
ブラックリスト方式の利点
柔軟な配布:初めにEAを広く配布し、その後で特定のユーザーに対して制限を加えることができます。これにより、ユーザーベースの迅速な拡大が可能です。
動的な管理:ユーザーの状態や条件が変化した場合(例:IBに紐付けされた場合)、リアルタイムで機能の制限やアップグレードを行えます。
マーケティング戦略:特定の条件を満たすことで追加機能が得られるというインセンティブを設定することで、ユーザーに対するマーケティング効果を高めることができます。
活用方法:IB紐付けによる機能アップグレード
ブラックリスト方式を活用する一つの方法は、IB紐付けを条件としてEAの追加機能を提供することです。例えば、すべてのユーザーに基本機能を提供し、IBに紐付けされたユーザーには高度なトレーディングツールやカスタマイズオプションを解放します。このアプローチは、新しいIBクライアントの獲得を促進すると同時に、EAの利用価値を高めることができます。
実装上の考慮事項
ブラックリスト方式を採用する場合、以下の点に注意が必要です:
セキュリティ:不正使用を防ぐために、セキュアな認証システムを構築することが重要です。
ユーザープライバシー:ユーザーのプライバシーを尊重し、関連する法律や規制に準拠することが必要です。
ユーザー体験:機能制限やアップグレードのプロセスがユーザーにとって透明でわかりやすいことを確保します。
まとめ
ブラックリスト方式の認証システムは、EAの配布と管理において柔軟性と効果的なマーケティングツールを提供します。特にIB紐付けなど特定の条件を満たしたユーザーへの機能アップグレードの提供において、このアプローチは大きな利点を持っています。ただし、実装にあたってはセキュリティ、プライバシー保護、ユーザー体験の3つの要素を慎重に考慮する必要があります。
以下はソースコードです。流れは前回のものと同じです。
`auth()` 関数では、HTTPリクエストを通じて得られるレスポンスに基づいて、異なる認証ステータスを返します。各ステータスコード(-1、0、1、2、3)は、特定の状況や条件に対応しています。以下に各ステータスコードの意味を説明します。
-1: DLLが許可されていない
このステータスは、MetaTrader 4(MT4)プラットフォームの設定でDLLの使用が許可されていない場合に返されます。
MT4では、セキュリティ上の理由からデフォルトではDLLの使用が制限されています。DLLを使用するためには、ユーザーが明示的に設定で許可する必要があります。
このエラーが発生した場合、ユーザーはMT4の設定を確認し、DLLの使用を許可する必要があります。
0: 仮認証
このステータスは、サーバーからのレスポンスが「0」であった場合、またはレスポンスが存在しない場合に返されます。
仮認証は、ユーザーが特定の条件(例:IBに紐付いている、特定のアカウント番号を持っているなど)を満たしていないが、基本的な機能は使用できる状態を指します。
1: 本認証
このステータスは、サーバーからのレスポンスが「1」であった場合に返されます。
本認証は、ユーザーが必要なすべての条件を満たしているため、EAの全機能が使用可能な状態を指します。
2: 制限
このステータスは、サーバーからのレスポンスが「2」であった場合に返されます。
制限は、ユーザーが特定の条件を満たしていないため、EAの一部機能に制限がかかっている状態を指します。
3: その他の場合
このステータスは、上記の条件に該当しない場合に返されます。例えば、デモモードやテストモードである、アカウント番号が0である、サーバーへの接続に失敗した場合などです。
この状態では、EAは基本的に無効または非機能的な状態となります。
これらのステータスコードは、EAの利用状況や認証プロセスを管理するために重要で、EAの機能やアクセスレベルを適切に制御するために使用されます。
インクルードファイル kyoka .mqh
// kyoka.mqh
#import "wininet.dll"
int InternetOpenW(string agent, int accessType, string proxyName, string proxyByPass, int flags);
int InternetConnectW(int internet, string serverName, int port, string userName, string password, int service, int flags, int context);
int HttpOpenRequestW(int connect, string verb, string objectName, string version, string referer, char& acceptTypes[], uint flags, int context);
bool HttpSendRequestW(int hRequest, string &lpszHeaders, int dwHeadersLength, uchar &lpOptional[], int dwOptionalLength);
int InternetReadFile(int, uchar &arr[], int, int &byte);
int InternetCloseHandle(int winINet); #import
#define DEFAULT_HTTPS_PORT 443
#define SERVICE_HTTP 3
#define FLAG_SECURE 0x00800000
#define FLAG_PRAGMA_NOCACHE 0x00000100
#define FLAG_KEEP_CONNECTION 0x00400000
#define FLAG_RELOAD 0x80000000
string your_url = "asia-northeast1-optical-legend.cloudfunctions.net";
string your_endpoint = "/kyoka1";
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int auth() {
if(IsDemo() || IsTesting()) {
Print("In Demo or Testing mode. Exiting.");
return 3;
}
if(AccountNumber()==0){
Print("Account number is 0. Exiting.");
return 3;
}
string host = your_url;
string UserAgent = "MT4 Authentication";
string nill = "";
Print("Opening Internet session...");
int session = InternetOpenW(UserAgent, 0, nill, nill, 0);
if (session == 0) {
Print("Error opening Internet session: ", GetLastError());
return 3;
}
Print("Connecting to server...");
int connect = InternetConnectW(session, host, DEFAULT_HTTPS_PORT, nill, nill, SERVICE_HTTP, 0, 0);
if (connect == 0) {
Print("Error connecting to server: ", GetLastError());
InternetCloseHandle(session);
return 3;
}
string Vers = "HTTP/1.1";
string Method = "GET";
string accountNumberStr = DoubleToString(AccountNumber(), 0);
string brokerName = AccountCompany();
string Object = your_endpoint + "?account_number=" + accountNumberStr + "&broker_name=" + brokerName;
string Types = "";
char acceptTypes[];
StringToCharArray(Types, acceptTypes);
int context = 0;
Print("Sending HTTP request...");
int hRequest = HttpOpenRequestW(connect, Method, Object, Vers, nill, acceptTypes, FLAG_SECURE | FLAG_KEEP_CONNECTION | FLAG_RELOAD | FLAG_PRAGMA_NOCACHE, context);
string headers = "Content-Type: application/x-www-form-urlencoded\r\n";
uchar body[];
int dwHeadersLength = 0;
int dwOptionalLength = 0;
bool hSend = HttpSendRequestW(hRequest, headers, dwHeadersLength, body, dwOptionalLength);
if (!hSend) {
Print("Error sending request: ", GetLastError());
InternetCloseHandle(hRequest);
InternetCloseHandle(connect);
InternetCloseHandle(session);
return 3;
}
uchar ch[100];
string toStr = "";
int dwBytes;
Print("Reading response...");
while(InternetReadFile(hRequest, ch, 100, dwBytes)) {
if(dwBytes <= 0) break;
toStr = CharArrayToString(ch, 0, dwBytes);
}
// Close handles
InternetCloseHandle(hRequest);
InternetCloseHandle(connect);
InternetCloseHandle(session);
if(!IsDllsAllowed()) {
Comment("DLLを許可してください。");
Alert("DLLを許可してください。");
return -1;
}
bool A = StringFind(toStr, "0") > 0 || StringToInteger(toStr) == 0;
bool B = StringFind(toStr, "1") > 0 || StringToInteger(toStr) == 1;
bool C = StringFind(toStr, "2") > 0 || StringToInteger(toStr) == 2;
Print("toStr:",toStr);
if(A) {
Comment("仮認証");
return 0;
}
if(B) {
Comment("本認証");
return 1;
}
if(C) {
Comment("制限0.1");
return 2;
}
return 3;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
EA本体に追加
#property strict #include <kyoka.mqh>
int ibStatus = 0;
int OnInit() {
ibStatus = auth();
if(ibStatus==-1){return -1;}
return 0;}
GCP
import functions_framework
from google.cloud import firestore
import datetime
# Initialize Firestore client
db = firestore.Client()
@functions_framework.http
def check_account_number(request):
"""HTTP Cloud Function to check account number.
Args:
request (flask.Request): The request object.
Returns:
The status of the account number.
"""
# Parse request arguments
request_args = request.args
if not request_args or 'account_number' not in request_args or 'broker_name' not in request_args:
print("Invalid request: Missing 'account_number' or 'broker_name'")
return 'Invalid request', 400
account_number = request_args['account_number']
broker_name = request_args['broker_name']
# Log the received parameters
print(f"Received parameters - Broker Name: {broker_name}, Account Number: {account_number}")
# Reference to the collection and document
broker_ref = db.collection(broker_name).document(account_number)
try:
# Attempt to retrieve the document
doc = broker_ref.get()
if doc.exists:
# Return the status if the document exists
print(f"Document exists - Broker Name: {broker_name}, Account Number: {account_number}")
return doc.to_dict().get('status', '0')
else:
# Create a new document if it does not exist
new_doc_data = {
'broker_name': broker_name,
'account_number': account_number,
'status': '0', # 仮認証
'update_date': datetime.datetime.now(),
'creation_date': datetime.datetime.now()
}
broker_ref.set(new_doc_data)
print(f"Created new document - Data: {new_doc_data}")
return '0' # Return the initial status
except Exception as e:
print(f"Error: {str(e)}")
return f'Error: {str(e)}', 500
functions-framework==3.*
google-cloud-firestore==2.1.3
この記事が気に入ったらサポートをしてみませんか?