銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

Azure Mobile Services でアクセス許可を制限した Custom API に カジュアルにアクセスする

Windows Azure Advent Calendar 2013 - Qiita [キータ] 16日目の記事です。

今日はAzure Mobile Services のCustom API にカジュアルにアクセスしてみたいと思います。Mobile ServiesにはWindows Store App, Windows Phone, Andoird, iPhoneなど各種クライアントSDKが用意されているのですが、開発中のテストのときとかはもっとカジュアルにアクセスしたいですよね?そう、アクセス許可を設定している状態でも、SDKなしに認証してアクセスしてみましょう。

Custom APIの作成とアクセス許可レベル

さて、このCustom APIですが、Mobile Serviceを作ったらAPIのページの下の作成ボタンから作成できます。

f:id:tanaka733:20131215011811p:plain

すると、apiの名前と各HTTPメソッドに対してのアクセス許可レベルを設定できます。

f:id:tanaka733:20131215012857p:plain

作成するとスクリプトが作成されます。スケジュールのスクリプト同様、node.js でHTTPのフレームワークのexpress.jsが使われています。

exports.get = function(request, response) {
    response.send(statusCodes.OK, { message : 'Hello World!' });
};

APIをカジュアルにアクセスする(認証なし)

とりあえず、このAPIをたたいてみましょう。単純にHTTPリクエストを送ればアクセスできます。 というわけで、カジュアルにコマンドラインから実行をしてみましょう。え、Windowsには curl コマンドが標準で入ってないからカジュアルにできないって?何をおっしゃるうさぎさん、Windowsには PowerShell が標準でついてきて、Invoke-WebRequest コマンドレットが使えます。

PS > Invoke-WebRequest https://tanaka733app.azure-mobile.net/api/sampleapi


StatusCode        : 200
StatusDescription : OK
Content           : {"message":"Hello World!"}
RawContent        : HTTP/1.1 200 OK
                    x-zumo-version: Zumo.Main.0.1.6.4247.Runtime
                    Content-Length: 26
                    Cache-Control: no-cache
                    Content-Type: application/json; charset=utf-8
                    Server: Microsoft-IIS/8.0
                    X-Powered-By: ASP....
Forms             : {}
Headers           : {[x-zumo-version, Zumo.Main.0.1.6.4247.Runtime], [Content-Length, 26], [Cache-Control, no-cache], [
                    Content-Type, application/json; charset=utf-8]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 26

ドメインはMobile Serviceを作成してダッシュボードに表示されているモバイルサービスURL、apiの次のパスはAPIの名前になります。

f:id:tanaka733:20131215013418p:plain

レスポンスが正しく返るのは、GETのアクセス許可がすべてのユーザーになっているためです。他のものにすると401が返ります。

PS > Invoke-WebRequest https://tanaka733app.azure-mobile.net/api/sampleapi
Invoke-WebRequest : {"code":401,"error":"Error: Unauthorized"}

アプリケーションキーで認証してアクセスする & 管理者としてアクセスする

では次はアクセス許可レベルを「アプリケーションキーを持つユーザー」にしたときにアクセスする方法です。アプリケーションキーを X-ZUMO-APPLICATION ヘッダーに指定してリクエストを送ります。

> Invoke-WebRequest -Uri https://tanaka733app.azure-mobile.net/api/sampleapi -Headers @{"X-ZUMO-APPLICATION"="ApplicationKey"}

アプリケーションキーは、Mobile Serviceのダッシュボードで下部のキーの管理を開くとアプリケーションキーとマスターキーが表示されます。

f:id:tanaka733:20131215020930p:plain

さて、アクセス許可レベル的には「認証されたユーザーのみ」なのですが、先に許可レベル「管理者」を試しましょう。キーの管理画面にあったマスターキーを X-ZUMO-MASTER ヘッダーに指定します。

> Invoke-WebRequest -Uri https://tanaka733app.azure-mobile.net/api/sampleapi -Headers @{"X-ZUMO-MASTER"="MasterKey"}

これでOKです。なお、当然のことですが、管理者しかアクセスできないようにするには、このマスターキーを外部に漏らしてはいけないので注意しましょう。適宜再生成するのもおすすめです。

認証されたユーザーとしてアクセスする

最後に「認証されたユーザー」のみ、を試してみます。アプリケーションキーを持つユーザーでなくて認証されたユーザーががあるのは、基本的にアプリケーションキーは公開される情報だからです。コードのバイナリとともに配布されますし、コードからHTTP通信でヘッダにつけて送信するため、アプリケーションのユーザーに(直接ではないが)公開される情報ですし、アプリケーションユーザー以外にも知られる可能性があります。それを認証されたユーザーのみアクセス可能にした上で、そのユーザーがアクセスできるか否かをスクリプト内で検証する必要があります。(認証自体はアカウントを持っていれば誰でもできるので)

というわけでここではアプリでの認証のやりかたから見てみましょう。Microsoftアカウント、Facebook、Twitter、Googleの4つが現在使えますが、みんな大好きTwitterの例で。

Register for Twitter authentication - Mobile Services

を参考にTwitterの開発者ページでアプリケーションを作成します。大事なのは、「Allow this application to be used to sign in with Twitter」にチェックを入れて保存することです。

アプリを作ったら、Mobile ServiceのIDのページで、作成したTwitterアプリのConsumer KeyとConsumer Secret Keyを入力して保存します。これで準備OKです。

Webブラウザを開いて、 https://tanaka733app.azure-mobile.net/login/twitter (このモバイルサービスの場合のURL。ドメインの最初はサービス名になる。) にアクセスします。するとTwitterの認証画面にリダイレクトされるはずなので、アプリを認証します。すると次のようなURLにリダイレクトされるはずです。

https://tanaka733app.azure-mobile.net/login/done#token=<jwt_token>

token の後の文字列がURLエンコードされたJSONになっているはずで、これがJSON Web Tokenと呼ばれる認証トークンになります。このJSONの authenticationToken の値を抜き取っておきます(自分の場合、1700byte以上というかなり長い文字列になりました)。認証した後に、この形式のURLにリダイレクトされるのはTwitter以外のアカウントでも同じになるようです。この値を 「X-ZUMO-AUTH」ヘッダーにつけてリクエストを送ると、Custom APIの認証が通るようになります。

> Invoke-WebRequest -Uri https://tanaka733app.azure-mobile.net/api/sampleapi -Headers @{"X-ZUMO-AUTH"="<jwt_token>"}

実際には、こうやって認証されたユーザーが正当なユーザーかどうかをMobile Service内のユーザーデータ(おそらくRDBに格納しているはず)と突き合わせて検証することになります。

というわけで無事にClient 側のSDKを使わずにカジュアルにアクセス許可を認証することができました。