銀の光と碧い空

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

Azure Mobile Services の .NET Backend でユーザー認証・認可する (Previewだと割と大変)

Windows Azure アドベントカレンダー 3/9分の記事です。

MobileServicesの.NET Backendについて書くつもりだったのですが、素晴らしいエントリが出てしまったので

Windows Azure モバイルサービスで ASP.NET Web API を試す ~とりあえずサンプル実行~ - miso_soup3

ネタどうしようかと考えていました。「MobileServicesでOWIN動いているなら、LightNode 動かせばいいんじゃね?」と思い立つも、デプロイするときに「ホスティング プロバイダーがまだ ASP.NET 4.5 をサポートしていません。」というエラーが出てしまい断念したため、割と普通にユーザー認証した上で、そのユーザーのIDを取得する方法について紹介したいと思います。

まず、APIのアクセスレベルについては、先に紹介したブログにある通り、[RequiresAuthorization(AuthorizationLevel.Application)] といった属性をつけて設定します。

  • Anonymous => すべてのユーザー
  • Application => アプリケーションキーを持つユーザー
  • User => 認証されたユーザーのみ
  • Admin => 管理者のみ

で、何もつけないと Applicationになるようです。

今回は、 User に設定してそのUserのIdを取得することにしましょう。

基本的な流れは、

Windows Store App と Azure Mobile Services で Microsoft アカウント認証を行う

のままなのですが、微妙に画面が変わっていたりします。

まず、Azureポータル側では、ID タブで設定します。

f:id:tanaka733:20140309023440p:plain

ここに入力する3つの値を取得するには、Live Connectの設定が必要です。Windowsストアアプリから設定をすすめていくケースで紹介します。Windowsストアアプリのプロジェクトを名前を登録したアプリと関連付けた上で、開発者ダッシュボードに移動します。

https://appdev.microsoft.com/StorePortals/ja-JP/Home/LoginLandingPage

登録したアプリのサービスを選びます。

f:id:tanaka733:20140309023924p:plain

右下の方の、「Live サービス サイト」というリンクを押して移動します。

f:id:tanaka733:20140309023815p:plain

すると、ひとまず3つの値が表示されます。

f:id:tanaka733:20140309024132p:plain

ひとまずAzureポータルにこの3つの値を入力して保存します。が、これだけだと動きません。 左側のタブから「API設定」に移動します。移動したら、「リダイレクト URL:」に自分のMobileServicesのURLを入力します(<アプリ名>.mobileservices.net)。これで保存したら準備完了です。

f:id:tanaka733:20140309024257p:plain

あとは、ストアアプリ側のコードは前のブログのまま動かせばログイン画面がでるはずです。

f:id:tanaka733:20140309024459p:plain

これで認証は完了です。MobileServicesのサンプルでついているストアアプリのプロジェクトであれば、

private IMobileServiceTable<TodoItem> todoTable = App.MobileService.GetTable<TodoItem>();

というように IMobileServiceTable というクライアントを使っているので、認証してあげた時に

user = await App.MobileService
                        .LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);
todoTable.MobileServiceClient.CurrentUser = user;

というようにCurrentUserプロパティに設定してあげます。これで「認証されたユーザーのみ」というアクセス権限のAPIを実行できるようになります。

さて、ここからですが、認証されたユーザーがどのユーザーなのかサーバー側で取得してみます。ユーザーのIDの取得については、どうも現在のMobileServices .NET BackendのAPIには用意されておらず直接HTTPヘッダーから取得する必要があります。クライアント側の認証情報は、「X-ZUMO-AUTH」というヘッダーのキーで、値にはJSON Web Token (JWT) が渡されています。このあたりについては以下のページが詳しいです

アプリと Web サイトのシングル サインオン (Live Connect)

まじめにパースするなら紹介されているリンク先のコードを使えばいいのですが、

LiveSDK/Samples/Asp.net/AuthenticationTokenSample/JsonWebToken.cs at master · liveservices/LiveSDK · GitHub

とりあえずお手軽には次のようなコードでIDとなるuidプロパティを取得できます。

var authToken = Request.Headers.GetValues("X-ZUMO-AUTH").Single();
//A.B.C のBの部分だけ取り出す
var text = authToken.Split('.')[1];
//文字列長が4の倍数になるまで=で右埋め
var base64Text = text.PadRight((text.Length + 3) / 4 * 4, '=');
var bytes = Convert.FromBase64String(base64Text);
var jsonText = Encoding.UTF8.GetString(bytes);
var json = JObject.Parse(jsonText);
var uid = json["uid"].Value<string>();

さて、ユーザーの認証とIDの取得まではなんとかできたのですが、MobileServices の .NET Backendはプレビュー版ということでできない機能も多そうです。自分がいまのところできないと思っているものを挙げておきます。もし、こうやればできるよ!というのがあれば教えてもらえるとうれしいです。

  • NewRelicアドオンによる監視(設定できるけどNewRelic側に表示されない)
  • リモートデバッグ(設定できるけど接続できない。ユーザーとパスワードはデプロイユーザーのものを利用)
  • 通知ハブの利用(通知ハブの接続文字列がわたってこない。Web.configや管理ポータル上で設定はできない。)
  • TableController,TableController以外のAPI Controller での ApiServices クラスの利用。これができないとログやプッシュ通知といった機能が利用できない
  • ASP.NET 4.5機能の利用(LightNodeがデプロイできない...)

ぜひ正式版公開にあわせてこれらの機能が利用可能になって、ソースも公開されるといいなあと期待しています。