Я решил это.Хитрость заключается в том, что AuthorizeFilter может включать схемы с перегрузкой конструктора.
var authorizeFilter = new AuthorizeFilter(new List<IAuthorizeData> {
new AuthorizeAttribute()
{
AuthenticationSchemes = authenticationSchemes
}
});
Затем мне нужно было написать собственное IPageApplicationModelConvention, которое будет применяться на уровне области.Методы по умолчанию работают на уровне папок и страниц.Я использовал исходный код Microsoft.AspNetCore.Mvc.RazorPages в качестве руководства.
public class AreaModelConvention : IPageApplicationModelConvention
{
private readonly string _areaName;
private readonly Action<PageApplicationModel> _action;
public AreaModelConvention(string areaName, Action<PageApplicationModel> action)
{
_areaName = areaName;
_action = action;
}
public void Apply(PageApplicationModel model)
{
if(string.Equals(_areaName, model.AreaName, StringComparison.OrdinalIgnoreCase))
{
_action(model);
}
}
}
Я написал несколько PageConventionCollectionExtensions, как это все делается в Microsoft.AspNetCore.Mvc.RazorPages .
public static class PageConventionCollectionExtensions
{
public static PageConventionCollection RequireAuthenticationSchemesForArea(this PageConventionCollection conventions, string areaName, string authenticationSchemes)
{
if (conventions == null)
{
throw new ArgumentNullException(nameof(conventions));
}
if (string.IsNullOrEmpty(areaName))
{
throw new ArgumentException(nameof(areaName));
}
var authorizeFilter = new AuthorizeFilter(new List<IAuthorizeData> {
new AuthorizeAttribute()
{
AuthenticationSchemes = authenticationSchemes
}
});
conventions.AddAreaModelConvention(areaName, model => model.Filters.Add(authorizeFilter));
return conventions;
}
public static IPageApplicationModelConvention AddAreaModelConvention(this ICollection<IPageConvention> pageConventions, string areaName, Action<PageApplicationModel> action)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
var convention = new AreaModelConvention(areaName, action);
pageConventions.Add(convention);
return convention;
}
}
Наконец, я могу зарегистрировать все это:
services.AddMvc()
.AddRazorPagesOptions(options =>
{
options.Conventions.AllowAnonymousToNonareas();
options.Conventions.RequireAuthenticationSchemesForArea("Admin", "Windows");
options.Conventions.RequireAuthenticationSchemesForArea("Api", "ApiKey");
})
Примечание. Код для AllowAnonymousToNonareas здесь не определен, но он очень похож.Я создал NonareaModelConvention с помощью этого метода Apply:
public void Apply(PageApplicationModel model)
{
if (model.AreaName == null)
{
_action(model);
}
}
и написал похожие методы расширения, чтобы связать его вместе.
Не забудьте включить для приложения как анонимную аутентификацию, так и аутентификацию Windows.