例えば REST API を提供していて、ブラウザ上から JavaScript で呼び出せるように、CORS 対応したい。でも、許可するのは登録してもらったオリジンだけにしたい。そんなとき。
Microsoft.AspNetCore.Cors.Infrastructure.ICorsPolicyProvider
を実装したクラスを用意し、DI コンテナに登録すればいい。
namespace CorsSample; using System.Threading.Tasks; using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; public class MyCorsPolicyProvider : ICorsPolicyProvider { public async Task<CorsPolicy?> GetPolicyAsync(HttpContext context, string? policyName) { // とりあえずの実装なので、ポリシー関係なく全適用 var origin = GetCorsOrigin(context.Request); if (origin != null) { if (await IsOriginAllowedAsync(context, origin)) { return Allow(origin); } } return null; } private CorsPolicy Allow(string origin) { return new CorsPolicyBuilder() .WithOrigins(origin) .AllowAnyHeader() .AllowAnyMethod() .Build(); } private async Task<bool> IsOriginAllowedAsync(HttpContext context, string origin) { origin = origin.ToLowerInvariant(); var dbContext = context.RequestServices.GetRequiredService<ApplicationDbContext>(); return await dbContext.ClientCorsOrigins .Where(x => x.Origin == origin) .AnyAsync(); } private string? GetCorsOrigin(HttpRequest request) { var origin = request.Headers["Origin"].FirstOrDefault(); var thisOrigin = request.Scheme + "://" + request.Host; if (origin != null && origin != thisOrigin) { return origin; } return null; } }
こいつを、AddCors した後に AddTransient で登録する。
using CorsSample; using Microsoft.AspNetCore.Cors.Infrastructure; var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorPages(); // CORS を登録し、 // ICorsPolicyProvider の実装を差し替える。 builder.Services.AddCors(); builder.Services.AddTransient<ICorsPolicyProvider, MyCorsPolicyProvider>(); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); // CORS ミドルウェアを組み込む app.UseCors(); app.UseAuthorization(); app.MapRazorPages(); app.Run();
本番では、許可済みオリジンを一定時間キャッシュしたほうがいい。