---
lang: ja-jp
breaks: true
---
# ASP.NET Core Web API に `API Key` による独自認証を追加する 2023-07-04
## 参考資料
> ASP.NET Core の API の認証・認可をカスタマイズする方法
> https://qiita.com/okazuki/items/f66976c8cd71ea99c385
> SWAGGER UI FOR API KEY AUTHENTICATION FLOW WITH .NET CORE 6
> https://gowthamcbe.com/2022/02/21/swagger-ui-for-api-key-authentication-flow-with-net-core-6/
## テンプレートよりソリューションを作成


## CustomAuthenticationHandler.cs
```csharp=
public class CustomAuthenticationHandler :
AuthenticationHandler<AuthenticationSchemeOptions>
{
public CustomAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder
)
: base(
options,
logger,
encoder
)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var (ok, name, role) = tryGetApiKey(Context);
if (!ok)
{
return Task.FromResult(AuthenticateResult.Fail("Invalid API Key"));
}
var p = new ClaimsPrincipal(
new ClaimsIdentity(
claims: new[]
{
new Claim(ClaimTypes.Name, name, ClaimValueTypes.String),
new Claim(ClaimTypes.Role, role, ClaimValueTypes.String)
},
authenticationType: "API KEY AuthType"
)
);
return Task.FromResult(
AuthenticateResult.Success(
new AuthenticationTicket(
principal: p,
authenticationScheme: "ApiKeyAuthenticationScheme"
)
)
);
}
(bool ok, string name, string role) tryGetApiKey(HttpContext context)
{
if (!context.Request.Headers.TryGetValue("API_KEY", out var apiKey))
{
return (false, "", "");
}
return apiKey.ToString() switch
{
"A" => (true , "a さん", "Admin"),
"B" => (true , "b さん", "User" ),
_ => (false, "" , "" ),
};
}
}
```
## WeatherForecastController.cs
```csharp=
[ApiController]
[Route("[controller]")]
//[Authorize] // add this line
[Authorize(Roles = "Admin")] // add this line
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
// 名前も返すように変更
Summary = $"{Summaries[Random.Shared.Next(Summaries.Length)]} [{HttpContext?.User?.Identity?.Name}]"
})
.ToArray();
}
}
```
## Program.cs
```csharp=
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// デフォルトのスキーマの名前を ApiKeyAuthenticationScheme にして、
// ApiKeyAuthenticationScheme というスキーマで CustomAuthenticationHandler を使うように設定する。
builder.Services
.AddAuthentication(
defaultScheme: "ApiKeyAuthenticationScheme"
)
.AddScheme<AuthenticationSchemeOptions, CustomAuthenticationHandler>(
authenticationScheme: "ApiKeyAuthenticationScheme",
configureOptions: options => { }
);
builder.Services.AddSwaggerGen(c =>
{
// Swaggerの画面に「Authorize」ボタンを追加する。
c.AddSecurityDefinition(
name: "ApiKeyDefinition",
securityScheme: new OpenApiSecurityScheme
{
Description = "ApiKey must appear in header",
Type = SecuritySchemeType.ApiKey,
Name = "API_KEY",
In = ParameterLocation.Header,
Scheme = "ApiKeyScheme"
}
);
// リクエストに "API_KEY" ヘッダが追加されるように構成する。
var key = new OpenApiSecurityScheme()
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "ApiKeyDefinition"
},
In = ParameterLocation.Header
};
var requirement = new OpenApiSecurityRequirement
{
{ key, new List<string>() }
};
c.AddSecurityRequirement(requirement);
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
// 認証認可を有効にする
app.UseAuthentication(); // add
app.UseAuthorization();
app.MapControllers();
app.Run();
```
## 実行結果
### 認証無し

### Aさんで認証

### Bさんで認証
