.NET Core 3.1でAzure Active Directory認証を行う

.NET Core3.1でAzure Active Directory(=AAD)認証を行う方法についてです。

[AngularでAzure Active Directory認証を行う](https://qiita.com/d0nchaaan/items/ea2d9573010c31801746) の続きです。

クライアントアプリケーション(Angular)からのリクエストのヘッダーにはjwtがあるので、jwtによるAAD認証でWeb APIを保護します。

## Startup.cs

```C#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Authentication.AzureAD.UI;
using Microsoft.AspNetCore.Authentication;

namespace AadSample
{
    public class Startup
    {
        public Startup(IHostEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                    .SetBasePath(env.ContentRootPath)
                    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                    .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfiguration Configuration { get; }

        // DIを定義
        public void ConfigureServices(IServiceCollection services)
        {
          // Azure ADのServiceをDIの定義を追加
          // Configuration.Bind("AzureAd", options)でappsettings.jsonから必要な接続情報を取得する
            services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
                .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
          // …他のDI
        }
      
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            if (!env.IsDevelopment())
            {
                app.UseSpaStaticFiles();
            }

            app.UseRouting();

            app.UseAuthentication(); // 追記
            app.UseAuthorization();  // 追記

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}");
            });

            app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });
        }
    }
}

```

## appsettings.json

`AzureAd`スキーマにAzureポータルで作成したAADの設定情報を記載する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/816de664-fc11-a275-deee-43d290c4f778.png)

```json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "{例：hogehoge}.onmicrosoft.com",
    "TenantId": "{ディレクトリ(テナント)ID}",
    "ClientId": "{アプリケーション(クライアント)ID}"
  },
  "AllowedHosts": "*"
}

```

## HogeController

認証が必要なControllerに対し`[Authorize]`属性を付与します。

```C#
[HttpGet]
[Route("GetWeatherForecast")]
[Authorize]
public IEnumerable<WeatherForecast> Get()
{
    var rng = new Random();
    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = rng.Next(-20, 55),
        Summary = Summaries[rng.Next(Summaries.Length)]
    })
    .ToArray();
}
```

## CustomFilterAttributeを使って認証を行う場合は
`IAuthorizationFilter`を継承します。

```C#
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;

namespace AadSample
{
    /// <summary>
    /// 認証フィルター
    /// </summary>
    public class CustomAuthorize : Attribute, IAuthorizationFilter
    {
        /// <summary>
        /// 認証チェック
        /// </summary>
        /// <param name="context"></param>
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var user = context.HttpContext.User;
            if (user.Identity.IsAuthenticated)
            {
                return; // 認証済みならAPIを実行
            }
            else
            {
                context.Result = new UnauthorizedResult(); // 未認証なら401を返す
            }
        }
    }
}

```



## 参考URL

[保護された Web API アプリを構成する - Microsoft identity platform | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/active-directory/develop/scenario-protected-web-api-app-configuration#bearer-token)