MNPとAPI 1.0の登場-サボテンのボランティア活動

まえがき



ITの長年の経験を通じて、多くの人は、有用で価値のあるものすべてを含む独自のAPIを作成したり、経験したりしており、特定の瞬間にパズルが開発され、独自のサボテンの成長と食べの段階が始まります。

1年の慣らしの後、さらなる修正と開発の前に、API自体とサービスを批判にさらすために、電話番号(ロシアのみ)でモバイルオペレーターを決定するためのサービスの結果の機能を共有したいと思います。

この記事には、貴重なコメントと引き換えに役立つと思われる人のために、テスト用のPHPの例があります;-)



モバイル奴隷制廃止に直面したマジックペンデル



2003年から2004年にさかのぼりますが、今思い出すと、顧客は電話代を補充するために紙のフォームに記入するようになりました。 オペレーターのグラフで、ユーザーはBeelineを示し、痛くて馴染みのあるコード916は、それがMTSであり、支払いが祝福されないことを明確に教えてくれました。クライアントは私に安心しました。

10年後、この手順はすでに法律で承認されており、最終的には機能しました。オペレーターからオペレーターへの番号の移植性を考慮して、IT専門家だけがオペレーターを番号で認識するトレーニングシステムの形で負荷のわずかな増加を受けました-MNP。



データの外観



いつものように、一元化されたものにはすべて単一のレジストリがあります。 この場合、それらの2つがありました。1つ-データはほとんど変更されていません-彼らは、たとえば916--のような大きなブロックのオペレーターに属していると判断しました。 2番目-動的な同じ転送された番号-つまり、各番号は個別のエントリでした。

技術的な詳細は省略します。 それは、個々の番号が「ハングアウト」している上に大きな層があるということだけでした-最初に、彼らは範囲演算子をすくい上げ、次に他の演算子への番号転送の記録があるかどうかを調べました。 レイヤーは、1か月に1回、個別の数値-1時間ごとに更新されました(数値が転送されるため)。



ストレージとアップデート



より資本的なアプローチが必要であることに気付いて、膝の上でそれをしないことを決めました...はい、そして膝は何ですか-ベースの動的な部分へのアクセスを得るための法的エンティティ間の完全な合意、規制された同期-これはこれらを使用した個々のプロジェクトにもはや縫い付けられていませんデータは面倒です。 センターははっきりと見えていました-データストレージの場所。

オフトピック:演算子の重要性について少し
コールセンターを想像してください。 彼は多くの呼び出しを行い、呼び出しの演算子を選択するためのさまざまなスキームを適用します。MGTS番号への呼び出しには、モバイルジャンクションが使用されます。 加入者が移行するにつれて、間違ったチャネルでますます多くのコールが行われたとき、それは悲しくなりました-間違ったチャネルは従業員のボーナス基金を容赦なく食べた非常に特定のルーブルの損失でした。





創発センター-API



データを提供する最初のスクリプトのペアをスケッチすることは、難しいことではありません。 しかし、それはあなた自身のためにすること、顧客側にある製品のための別のことです。 さらに、便利なAndroidアプリケーションのアイデアは空中にあり、外部の世界へのアクセス、アプリケーションの「破壊」を目的とした攻撃の可能性を既に感じていました。shkolotaは、好奇心と自己肯定から何かを打ち破りたいことがあります。 したがって、明示的なFRONT-END、AAA、BACK-END、および要求ハンドラーが突然表示されます。

ハンドラーについて...
バックエンドのどこかでAPIクライアントリクエストをその場で処理したくありませんでした。ディスクリクエストを追加して、簡単にスケーリングできる多数の個別のサーバーで処理する方がずっと面白かったです。 その上で同意した。



目に見える要件:





「Hello World!」-最も単純な例で最も難しい



これが最も興味深いものです。 APIの呼び出しは承認から始まります-システムとのさらなる対話のためのトークンを取得します。 入力として、最大3つの識別値(ユーザー名、電話番号、電子メール+パスワード)が使用されます。

ショザブレッド!?
私たちの生活には多くの変数があります。

  • 企業の電子メールは、以前の職場から持ち去ることは許可されていませんでした
  • 電話は出張中に手に負えない状態になり、オペレーターが電話番号を取得しました
  • パスワードが侵害されています


そのため、ユーザー名のみが不変であり、それでも「さようなら」、それは私には思えます。 そして、他のすべては非常に一貫性がありません...そして、他の2人の存在下で1つの属性を変更することは問題ではなく、いくつかの段階での承認と完全に同等です(2要素)。



アカウントごとに時間単位ごとに1つのトークンのみが発行されます。 変更することができます。これにより、その下で機能したスクリプトおよびアプリケーションの権限が「取り消され」ます。 これは良いことも悪いこともありますが、最も重要なことは、制御された方法です。

トークンノート
サービスの1つは、アカウントを登録するように設計されています。

サイト訪問者がサードパーティのサイトでサービスの一部の機能を使用したいと考えていることを想像してください-サイト自体が新しいアカウントを要求し、承認(=トークンを受信)し、Webブラウザーセッションのパラメーターでサービスと対話するためのトークンを通知します。 ブラウザーを使用すると、ユーザー自身がリクエストを行うことができますが、ポータル内だけでなくセッションの「ステアリングホイール」がありますが、ユーザーが情報にアクセスする必要がなくなったと考える場合、トークンを変更することで外部APIへのアクセスを簡単に閉じることができます。



ただし、最初に、SSLを使用しない安全でないネットワーク上で対話用の公開キーを取得してから、データを準備します。

ケーススタディ:「SSLは拒否されました」
443のポートにアクセスできない可能性があります。「大規模なオフィスのセキュリティサービスのパラノイアの1つを今でも覚えています。



$rsa_key = file_get_contents ('http://core.api.netresult.ru/rsa_public.pem'); $client_secret = md5(time()); $data = json_encode( array ('request_type' => 'auth', 'username' =>'habr_demo_20160426', 'email' => 'support@media24-corp.ru', 'phone' => '74995799366', 'password' => md5('megapass'), 'client_secret' => $client_secret) ); $pk = openssl_get_publickey($rsa_key); openssl_public_encrypt($data, $encrypted, $pk); $data = array('body' => chunk_split(base64_encode($encrypted)));
      
      







これは単純な要求のための悪夢です。この一連の操作は、通信チャネルを介した送信中のデータ変更を警告し、FRONT-END'eで簡単に検証できるように設計されています。

 function api_build_url ( $scheme='https', //  - http|https $domain='core.api.netresult.ru', //  API,   - core.api.netresult.ru $validation_string_prefix='s', //   ,    (   ) $validation_secret='earth', //    ,   FRONT-END -  FRONT-END`    URI (   URI) $data='', // POST .     $data['body'] $api_version='3', //  API,      $sla=1, //  SLA.  - .  ,  .    .      -   ,     ,   . $uid=0, //     API (AAA). 0  ,    UID $srv_name='AUTHENTICATE', // ,          $client_secret //   ,    .    ,   API    . ) { $url_template = $scheme . '://' . $domain . '/' . $validation_string_prefix . '/__NGINX_SIGN__/__QUERY_STRING__'; $request_string = 'v' . $api_version . '-sla' . $sla . '-uid' . $uid . '-sign__SOMESIGN__-req' . $srv_name; $request_string = str_replace ('__SOMESIGN__', $client_secret, $request_string); $request_string .= '=ts:' . time(); echo "request_string before md5: " . $request_string . PHP_EOL; if (isset($data['body']) === true) { $request_string .= '=postmd5:' . md5($data['body']); } $request_string = str_replace($client_secret, md5($request_string), $request_string); $url = str_replace ('__QUERY_STRING__', $request_string, $url_template); $request_string .= $validation_secret; $query_sign = md5($request_string); $url = str_replace ('__NGINX_SIGN__', $query_sign, $url); return $url; }
      
      







最後に、許可を得ました-トークンとUIDを取得します。 この操作は、シークレット/トークンを変更する必要がない場合、アカウントが存在するすべての時間に対して1回実行できます。

 $url = api_build_url ('http', 'core.api.netresult.ru', 's', 'earth', $data, '3', 1, 0, 'AUTHENTICATE', $client_secret); $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'POST', 'content' => http_build_query($data), ), ); $context = stream_context_create($options); $result = file_get_contents($url, false, $context); print_r ($result); /* secret: 50c927316191f8678cec3b5247d1b34f request_string before md5: v3-sla1-uid0-sign50c927316191f8678cec3b5247d1b34f-reqAUTHENTICATE=ts:1461624725 {"response":{"code":"200","data":{"uid":"36","sla":"1"},"msg":"authenticated"}} */
      
      







それ以上の資格情報は使用されません-署名用の$ client_secretのみ。 ところで、私はすぐに質問に答えます-はい、リクエストがまれでリソースを節約する目的がない場合(またはクライアントのブラウザー側で費やされる場合)、SSLを使用した対話の関数パラメーターでhttpsを指定できます。 、ただし、クライアントは必要に応じてSSLを介して独自のトークンでリクエストを実行できます。



だから、ログインしました。 次に、正しいUIDとSLAを自分で割り当て、テストリクエストを実行します。

 $uid = $result['response']['data']['uid']; $sla = $result['response']['data']['sla']; echo PHP_EOL . PHP_EOL . "TEST SERVICE:" . PHP_EOL; $url = api_build_url ('http', 'core.api.netresult.ru', 's', 'earth', '', '3', $sla, $uid, 'TEST', $client_secret); $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'GET' ), ); $context = stream_context_create($options); $result = file_get_contents($url, false, $context); print_r ($result); /* TEST SERVICE: request_string before md5: v3-sla1-uid36-sign50c927316191f8678cec3b5247d1b34f-reqTEST=ts:1461624725 {"response":{"code":"200","data":{"id":"21967","sla":"1","uid":"36","sign":"9cf6cba26113c52abea3af928f6232b6","srv":"test","req_head":"TEST=ts:1461624725","req_body":"","api_version":"3"},"msg":"ok"}} */
      
      





うん、大丈夫!



便益



同様に、より便利なサービスLOOKUP_BY_NUMBERを使用します。これには追加のパラメーターが必要です。

number - ( "+")

source - (all - ),







必要に応じて追加のフィールドを設定できます(たとえば、モバイルアプリケーションで、デバイス自体を識別し、応答を正しく形成するため)

v -

did -

loc -

format -







 echo PHP_EOL . PHP_EOL . "LOOKUP_BY_NUMBER SERVICE:" . PHP_EOL; $url = api_build_url ('http', 'core.api.netresult.ru', 's', 'earth', '', '3', $sla, $uid, 'LOOKUP_BY_NUMBER'.'=number:+79671286464=v:6=loc:ru_RU=did:000000000000000000000000=format:no=source:all', $client_secret); $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'GET' ), ); $context = stream_context_create($options); $result = file_get_contents($url, false, $context); print_r ($result); /* LOOKUP_BY_NUMBER SERVICE: request_string before md5: v3-sla1-uid36-sign0e70a22605e5a178b572f0bfe426d210-reqLOOKUP_BY_NUMBER=number:+79671286464=v:6=loc:ru_RU=did:000000000000000000000000=format:no=source:all=ts:1461625693 {"response":{"code":200,"data":{"input":{"number":{"original":"+79671286464","parsed":"79671286464"}},"route":{"default":{"ServiceProvider_id":"3425721","ServiceProvider_name":" \"-\"","ServiceProvider_region":".    "},"mnp":{"ServiceProvider_id":2,"ServiceProvider_name":"\" \" ","ServiceProvider_region":".    "}},"active_route":{"type":"mnp"}},"msg":""}} */
      
      







戻り値


クエリの結果、ルーティングテーブルは優先度順になります。 最初のソースレコードがアクティブです。 残りは単にデータベースにありますが、ほとんどの場合古くなっています。 出力は、適切な「フォーマット」設定に依存します。

重要:サービスプロバイダーIDは、各データソースに対して内部的に返されます! 1つのソース内でIDごとに安全に統合できます。



出力例:

 { "response": { "code": 200, "data": { "input": { "number": { "original": "+79781234567", "parsed": "79781234567" } }, "route": { "default": { "ServiceProvider_id": "274959", "ServiceProvider_name": " ", "ServiceProvider_region": " " } }, "active_route": "default" }, "msg": "" } }
      
      







データ送信方法


最も簡単なGETメソッドを使用できます。例:

http://core.api.netresult.ru/s/f62bb062e30b01e7a689c8cdfdf10577/v3-sla1-uid0-signbb52d15783f7ed30df5d0e7a618cc048-reqLOOKUP_BY_NUMBER=number:+79781234567=v:6=loc:ru_RU=did:000000000000000000000000=format:no=source:all







上記の認証の例を使用して、POSTデータの変数の値を暗号化して送信できます。



アプリケーション自体の最小限の機能を備えたAndroid用の APIベースのモバイルアプリケーションの例。

画像





コメントとレビュー



あなたがコメントするために必要だと思うすべてのものについての批判に非常に感謝しています!



All Articles