5/29-30 de:code セッション SV-007 “パワフル モバイル アプリ開発 ~ 最新 Microsoft Azure Mobile Services をフル活用しよう!~ ” フォローアップ (4)

皆様、こんにちは!多くの方に (1) (2) (3) を読んでいただいて、大変感謝しています。

今回は、4番目のセッションフォローアップである、Microsoft Azure Active Directory 連携、に行きたいと思います。

セッションでもご紹介した通り、主に、Azure ポータル上で必要な手順と、ADAL(Active Directory Authentication Library)を使ったネイティブアプリの認証コードの記述、に分かれますので、順にご紹介していきます。

1.Azure ポータル上で必要な手順ーWebアプリ(Mobile Services のプロキシであるWebSites)の登録

まず最初に、アプリが Azure Active Directory を認証プロバイダーとして使用してMobile Services にログインできるように登録する方法をご紹介します。

Azure ポータルにログインし、Mobile Services タブをクリックして、対象のMobile Services をクリックします。image

Identity(ID) タブをクリックします。

image

Azure Active Directory の箇所まで、当該セクションをスクロールダウンし、リストされている アプリケーション URL をコピーします。

image 

管理ポータルから Active Directory に移動し、自分で作った Active Directory をポイントします(まだ作ってない場合には、新規作成ですぐに作りましょう)。もちろん、ユーザーも登録しておく必要があります。

image 

アプリケーション タブをクリックし、 アプリを 追加します。

image

画面下部の追加ボタンを押して、組織で開発中のアプリケーションを追加 をクリックします。

image

アプリケーションの追加ウィザードの中で、アプリケーションの名前を適当に入力し、Web Application 及びまたは Web API タイプを選択して続けます。

image

サインオン URL ボックスで、先述した Mobile Services の Active Directory IDプロバイダー設定からコピーした App ID を貼り付けます。同じく、アプリケーション ID/URI も同じものを張り付け、保存します。このアプリは、この URI を使って、シングルサインオンのリクエストを、Azure Active Directory に送信します。継続ボタンをクリックします。

image 

アプリケーションが追加されたら、 構成タブをクリックします そして、 発行されたクライアント ID をコピーします。

image

Mobile Services の ID タブに戻ります。画面下部に、Azure Active Directory 用の Client ID 設定がありますので、そこにこの値を張り付けてして保存します。

image

※ .NETバックエンドを採用している場合(本稿もそうです)、Allowed Tenants リストが見えます。ここですべてのドメインを登録する必要があります(例: contoso.onmicrosoft.com) 。これを使って Mobile Services が Allowed Tenants リストにアクセスします。この設定は、Node.js(JavaScript)バックエンドには適用されません。

保存すると、Azure Active Directory を使って、このアプリの認証を行うことができます。

2.Windows ストアアプリ Mobile Services クライアントによる Azure Active Directory へのシングルサインオン

 

Azure 管理ポータルで、Azure Active Directory に戻ります。アプリケーション タブをクリックし、アプリケーションを選択します。

マニフェストの管理をクリックして、マニフェストのダウンロードを選び、アプリケーションマニフェストをローカルに保存します。

image 

Visual Studio でこのマニフェストファイルを開きます。ファイルの先頭にある、apPermissions 部分を探します。

    1: "appPermissions": [],

この部分を適宜変更して保存します。PermissionId の部分はもちろんこのままではなく、適宜変更してください。

    1: "appPermissions": [
    2:     {
    3:         "claimValue": "user_impersonation",
    4:         "description": "Allow the application access to the mobile service",
    5:         "directAccessGrantTypes": [],
    6:         "displayName": "Have full access to the mobile service",
    7:         "impersonationAccessGrantTypes": [
    8:             {
    9:                 "impersonated": "User",
   10:                 "impersonator": "Application"
   11:             }
   12:         ],
   13:         "isDisabled": false,
   14:         "origin": "Application",
   15:         "permissionId": "b69ee3c9-c40d-4f2a-ac80-961cd1534e40",
   16:         "resourceScopeType": "Personal",
   17:         "userConsentDescription": "Allow the application full access to the mobile service on your behalf",
   18:         "userConsentDisplayName": "Have full access to the mobile service"
   19:     }
   20: ],

PermissionId は、エンドポイントの表示をクリックすると、取得できます。

image

Azure 管理ポータルで、当該アプリのためのマニフェスト管理 をもう一度選択して、マニフェストのアップロードを選択します。ローカルにある、更新された当該マニフェストファイルの位置を指定して、アップロードします。

Azure Active Directory へのストアアプリの登録

Azure Active Directory へのストアアプリの登録には、このアプリを、Windows ストアに関連付けして、Package Security Identifier (通称:SID) を取得する必要があります。この SID を、Azure Active Directory の中のネイティブアプリケーションの設定の中に登録します。

新しい名前を付けたストアアプリのストアとの関連付け
Visual Studio で、ストアアプリのプロジェクトを右クリックして、ストアアプリケーションとストアとの関連付けを選択します。
image
Windowsストアデベロッパーセンターにログインします。アプリ名を適当に入力して、 アプリ名を予約します。セッションでもご紹介した通り、予約は1年間は有効です。ストアで公開しないにしても、予約はしておきましょう。
image

image

適当な名前を付けて、次へ をクリックします。アプリとストアでの名前との関連付けをするをクリックすると、パッケージ SID が取得できます。パッケージ SID を取得するため、Windows ストアアプリ開発者ポータルのダッシュボードにログオンし、対象アプリの編集をクリックします。
image

そしてサービスをクリックします。

image

ライブサービスのサイトに移動します。 

image

パッケージ SID をコピーして、Azure Active Directory にペーストします。

image

ネイティブアプリの登録
Azure 管理ポータルで、 Azure Active Directory に移動し、 ディレクトリを展開します。
image 

アプリケーション タブをクリックし、 アプリを 追加します。

image

画面下部の追加ボタンを押して、組織で開発中のアプリケーションを追加 をクリックします。

image

アプリケーションの追加ウィザードの中で、アプリケーションの名前を適当に入力し、ネイティブクライアントアプリケーションタイプを選択して続けます。

image
リダイレクト URI ボックスに、先ほどコピーした、パッケージ SID をペーストし、保存して登録を終了します。。
 image
ネイティブアプリの構成 タブをクリックし、 クライアント ID をコピーします。後で必要となります(適宜、ロゴなどもアップロードします)。
image
ページをスクロールダウンして、他のアプリケーションに対するアクセス許可セクションに移動します。そして、該当する登録済み Mobile Services アプリケーションに対するフルアクセスを設定し、保存をクリックします。

image

これで、Mobile Services は、アプリからのログイン要求を、Azure Active Directory の中でシングルサインオンを要求するように、構成されました。

Mobile Services コントローラー側を認証を要求するように修正

ついで当該Mobile Services の .NET バックエンド側を、認証が必要なように、修正します。

.NET バックエンドのプロジェクトを開きます。ソリューションエクスプローラーで、Controllers フォルダを開き、 ProductWithPriceController.cs ファイルを開き、下記の通り、編集します。。

    1: using Microsoft.WindowsAzure.Mobile.Service.Security;

ProductWithPriceController.cs ファイル内のすべてのメソッドに、 [AuthorizeLevel(AuthorizationLevel.User)] 属性を、追加して、保存します。プロジェクトを右クリックして、リビルドします。そして、Azure に、再度発行(パブリッシュ)します。

    1: ・・・
    2: // GET tables/ProductWithPrice
    3:  [RequiresAuthorization(AuthorizationLevel.User)]
    4: public IQueryable<ProductWithPrice> GetAllProductWithPrice()
    5: {
    6:     return Query(); 
    7: }
    8:  
    9: // GET tables/ProductWithPrice/48D68C86-6EA6-4C25-AA33-223FC9A27959
   10:  [RequiresAuthorization(AuthorizationLevel.User)]
   11: public SingleResult<ProductWithPrice> GetProductWithPrice(string id)
   12: {
   13:     return Lookup(id);
   14: }
   15:  
   16:  
   17: // PATCH tables/ProductWithPrice/48D68C86-6EA6-4C25-AA33-223FC9A27959
   18:  [RequiresAuthorization(AuthorizationLevel.User)]
   19: public Task<ProductWithPrice> PatchProductWithPrice(string id, Delta<ProductWithPrice> patch)
   20: {
   21:      return UpdateAsync(id, patch);
   22: }
   23:  
   24:  [RequiresAuthorization(AuthorizationLevel.User)]
   25: // POST tables/ProductWithPrice/48D68C86-6EA6-4C25-AA33-223FC9A27959
   26: public async Task<IHttpActionResult> PostProductWithPrice(ProductWithPrice item)
   27: {
   28:     ProductWithPrice current = await InsertAsync(item);
   29:     return CreatedAtRoute("Tables", new { id = current.Id }, current);
   30: }
   31:  
   32: [RequiresAuthorization(AuthorizationLevel.User)]
   33: // DELETE tables/ProductWithPrice/48D68C86-6EA6-4C25-AA33-223FC9A27959
   34: public Task DeleteProductWithPrice(string id)
   35: {
   36:      return DeleteAsync(id);
   37: }
   38: ・・・ 

ストアアプリへの認証コードの追加

このままストアアプリを実行すると、当然ながら、401のエラー(Unauthorized)が返ってきます。

screenshot_06082014_184033

そこで、認証の ためのコードを追加します。ソリューションエクスプローラーで、ストアアプリのプロジェクトを右クリックして、NuGet パッケージの管理を右クリックします。

NuGet パッケージマネージャーのダイアログで、オンラインプレリリースを含んだ形で、検索します。検索ボックス内に、Microsoft.IdentityModel.Clients と入力して、Active Directory Authentication Library が見つかったら、インストール をクリックして、Active Directory Authentication Library Nuget package をインストールします。

image

ソリューションエクスプローラーで、MainPage.xaml.cs を開いて、下記の using 句を追加します。

    1: using Windows.UI.Popups;
    2: using Microsoft.IdentityModel.Clients.ActiveDirectory;
    3: using Newtonsoft.Json.Linq;

MainPage クラスに、AuthenticateAsync() メソッドを追加します。

    1: private MobileServiceUser user; 
    2: private async Task AuthenticateAsync()
    3: {
    4:     string authority = "<INSERT-AUTHORITY-HERE>";
    5:     string resourceURI = "<INSERT-RESOURCE-URI-HERE>";
    6:     string clientID = "<INSERT-CLIENT-ID-HERE>"; 
    7:     while (user == null)
    8:     {
    9:         string message;
   10:         try
   11:         {
   12:           AuthenticationContext ac = new AuthenticationContext(authority, false);
   13:           AuthenticationResult ar = await ac.AcquireTokenAsync(resourceURI, clientID);
   14:           JObject payload = new JObject();
   15:           payload["access_token"] = ar.AccessToken;
   16:           user = await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
   17:           message = string.Format("You are now logged in - {0}", user.UserId);
   18:         }
   19:         catch (InvalidOperationException)
   20:         {
   21:           message = "You must log in. Login Required";
   22:         } 
   23:         var dialog = new MessageDialog(message);
   24:         dialog.Commands.Add(new UICommand("OK"));
   25:         await dialog.ShowAsync();
   26:     } 
   27: }

・INSERT-AUTHORITY-HERE は、テナント名です。フォーマットは、https://login.windows.net/tenant-name.onmicrosoft.com となります。こちらは、Azure ポータル内の Azure Active Directory から取得します。先ほども出てきました。

INSERT-RESOURCE-URI-HERE は、Mobile Services の App ID URI です。プロキシサービスとして機能する Websites です。フォーマットは、 https://todolist.azure-mobile.net/login/aad となります。これも既出です。

INSERT-CLIENT-ID-HERE の箇所は、Azure Active Directory で設定したネイティブクライアントアプリのページから、クライアント ID を取得してください。これも既出です。

Package.appxmanifest ファイルの設定

ソリューションエクスプローラーで、ストアアプリ内の Package.appxmanifest ファイルを開きます。機能タブを開いて、エンタープライズ認証と、プライベートネットワーク(クライアントとサーバー)にチェックをして保存します。

image

MainPage.cs に戻り、OnNavigatedTo イベントハンドラを、下記の通り編集し、AuthenticateAsync() メソッドを呼ぶように変更します。

    1: protected override async void OnNavigatedTo(NavigationEventArgs e)
    2: {
    3:     if (user == null)
    4:         await AuthenticateAsync();
    5:  
    6:     RefreshTodoItems();
    7: }

アプリをリビルドして、実行し、このような画面が出てくればOKです。Azure Active Directory に作成済みのユーザーで、ログインしましょう。

screenshot_06082014_190919

なお、セッションでは、DEMOとして、これ以外に、Office 365 連携アプリ(SQL Database とExchange Online の両方に予定を書き込む) もご紹介しましたが、こちらは別途、サブスクリプションが必要となりますので、こちらは割愛します。興味のある方は、弊社エバンジェリスト・松崎のブログ等をご参照ください。また、資料には、このあたりのフローも入れてありますので、ご参考まで!

以上です。いかがでしたか?

次回は、最後の(5)、として、Xamarin 連携の箇所を簡単に取り上げて、このセッションのフォローアップを終了としたいと思います。

それでは、また!

鈴木 章太郎