ROMANCE DAWN for the new world

Microsoft Azure を中心とした技術情報を書いています。

OWIN で ASP.NET Web API を Windows Azure Active Directory 認証する

gooner.hateblo.jp

前回の投稿では OWIN でマルチホストしましたが、今回はミドルウェアの Windows Azure Active Directory(WAAD)認証ライブラリを利用して、ASP.NET Web API を OAuth 2.0 認証してみます。元ネタはこちらですが、Visual Studio のテンプレート機能を使わずに、手動で構築します。

また、ネイティブ クライアント アプリからの認証では、Active Directory Authentication Library(ADAL)がいい感じなので、使ってみました。ADAL は、WAAD 向けの認証ライブラリで、以前は Windows Azure Authentication Library として提供されていたライブラリが名称変更されています。

Web API アプリを作成

Web アプリのテンプレートから Empty を選択し、Web API のみチェックして WebApiApp プロジェクトを新規作成します。GETで"api/test"にリクエストすると、ユーザー名を返すシンプルな Web API を追加し、忘れずに Authorize 属性を付けます。デバッグ実行し、レスポンスに 401 が返ることを確認しつつ、localhost のポート番号をメモしておきます。

#TestController.cs
[Authorize]
public class TestController : ApiController
{
    public string Get()
    {
        return base.User.Identity.Name;
    }
}

Web API アプリを WAAD に登録

ポータルから WAAD に、Web API アプリを追加します。ここでは、WAAD のドメイン名を「example.onmicrosoft.com」とします。新規に WAAD を作成する場合、一度作成すると削除できないようなので、ご注意ください。ウィザード画面で必要な情報を入力します。

add-webapp

ここでは、以下のように設定しました。

Web API アプリに WAAD 認証を追加

WebApiApp プロジェクトに NuGet パッケージをインストールします。

  • Install-package Microsoft.Owin.Host.SystemWeb
  • Install-package Microsoft.Owin.Security.ActiveDirectory

OWIN パイプラインに WAAD 認証のライブラリを追加します。Audience には、ポータルに登録した WebApiApp の APP ID URI を設定します。

#Startup.cs
[assembly: OwinStartup(typeof(WebApiApp.Startup))]
namespace WebApiApp
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseWindowsAzureActiveDirectoryBearerAuthentication(
                new WindowsAzureActiveDirectoryBearerAuthenticationOptions
                {
                    Audience = "https://example.onmicrosoft.com/WebApiApp",
                    Tenant = "example.onmicrosoft.com"
                });
        }
    }
}

ネイティブ クライアント アプリを WAAD に登録

ポータルから WAAD に、ネイティブ クライアント アプリを追加します。ウィザード画面で必要な情報を入力します。

add-wpfapp

ここでは、以下のように設定しました。

WpfApp を登録後、さきほど登録した WebApiApp との関連付けを行っておきます。

webapis

ネイティブ クライアント アプリを作成

WPFアプリとして、WpfApp プロジェクトを新規作成します。ネイティブ クライアント アプリの認証では、Webブラウザコントロールを利用した面倒な実装が必要となるのですが、Active Directory Authentication Libraryを使うと、このあたりの実装をライブラリが行ってくれます。WpfApp プロジェクトに NuGet パッケージをインストールします。

  • Install-package Microsoft.IdentityModel.Clients.ActiveDirectory
  • Install-Package Microsoft.AspNet.WebApi.Client

ボタンクリックイベントで WAAD 認証して、WebAPI を呼び出すシンプルなアプリです。9行目のコードで ADAL が認証してくれますので、取得した Bearer トークンをHTTPヘッダーに設定すれば OK です。WpfApp の Client ID は、ポータルから取得できます。

#MainWindow.xaml.cs
private async void Button_Click(object sender, RoutedEventArgs e)
{
    var authority = "https://login.windows.net/example.onmicrosoft.com";
    var appId = "https://example.onmicrosoft.com/WebApiApp";                // WebApiApp の APP ID URI
    var clientId = "c3d3af4a-1682-4e49-abd8-4a8e580cebf1";                   // WpfApp の Client ID
    var redirectUri = new Uri("https://example.onmicrosoft.com/WpfApp"); // WpfApp の REDIRECT URI
 
    // Windows Azure Active Directory 認証
    var authRes = new AuthenticationContext(authority).AcquireToken(appId, clientId, redirectUri);
 
    // 取得したトークンで、Web API を呼び出し
    var client = new HttpClient();
    client.DefaultRequestHeaders.Add(HttpRequestHeader.Authorization.ToString(), authRes.CreateAuthorizationHeader());
    var result = await client.GetStringAsync("http://localhost:61249/api/test");
    this.textBlock1.Text = result;
}

実行結果

まず、ネイティブ クライアント アプリからサインインするユーザーを、ポータルから登録しておきます。ここでは、WAAD のユーザー名を「tony@example.onmicrosoft.com」とします。

WpfApp のボタンをクリックすると、サインイン画面が表示され、認証に成功すると WebAPI から結果を取得できます。

signin

wpfresult

まとめ

クラウドで Web API を公開するなら、セキュリティは避けては通れない道です。OWIN のミドルウェアで提供されるフレームワークやライブラリを自由に組み合わせて、Web アプリを構築できる時代が始まっているのだと実感しました。