У нас есть IAuthorizationFilter
, и мы можем использовать его для авторизации запросов.
Но есть одна проблема. Я должен поддерживать несколько фильтров авторизации, например:
BearerTokenAuthorizationFilter
ApiKeyAuthorizationFilter
Я бы получил такое поведение:
Во-первых, BearerTokenAuthorizationFilter
проверяет, начинается ли заголовок авторизации с Bearer
. Если нет, то если для текущего действия применим другой фильтр авторизации, то запускаем этот другой фильтр авторизации. Если нет, верните ошибку «HTTP 401 Unauthorized».
И то же самое с ApiKeyAuthorizationFilter
. В начале он проверяет, начинается ли заголовок авторизации с Basic
. Если нет, проверяет, существует ли другой фильтр авторизации, и если да, то запускает его. В противном случае вернуть ошибку «HTTP 401 Unauthorized».
И чтобы предотвратить бесконечный цикл, нам нужно как-то хранить информацию о том, что конкретный фильтр авторизации уже был выполнен.
Это легко сделать в AuthenticationHandler
. Мы можем вернуть AuthenticateResult.NoResult()
, когда конкретный AuthenticationHandler
неприменим для обработки этого запроса, и будет запущен другой. Если все было выполнено, то вернуть 401 Unauthorized.
Так что у меня был бы такой же механизм, как и для AuthenticationHandler
(AuthenticateResult.NoResult()
). Как я могу добиться этого, используя AuthorizationFilter
?
Я могу, но это не работает. Если один из фильтров авторизации дает сбой, то другие не запускаются. Поэтому я не могу поддерживать множество фильтров авторизации для одного действия (не могу поддерживать разные методы авторизации для одного действия).
Несколько экземпляров AuthorizeAttribute обрабатываются MVC, как если бы они были объединены с помощью AND. Если вам нужно поведение ИЛИ, вам нужно будет реализовать собственную логику для проверок. Желательно реализовать AuthAttribute
Есть два способа
Любые примеры первого подхода? Я не понимаю, как я могу добиться поведения ИЛИ с помощью пользовательского фильтра аутентификации, если я хочу, чтобы многие фильтры авторизации в одном действии имели поведение ИЛИ.
В статье, на которую вы ссылались, используется ASP NET MVC. Это не работает в ASP NET Core с NET 7.
Это просто идея, стоящая за этим. Вот основная версия google.com/amp/s/www.infoworld.com/article/3622962/…
Я думаю, вы можете сделать Policy based
Авторизацию. Поэтому для этого вам нужно написать пользовательскую политику. вы можете проверить несколько случаев в рамках одной политики
это объясняется здесь
Я сделал то же самое, используя пользовательские политики, как показано ниже.
public sealed class CompanyAccessRequirementHandler : AuthorizationHandler<CompanyAccessRequirement>
{
private readonly ILoggedInUserService _loggedInUserService;
private readonly IUserSecurityRespository _userSecurityRespository;
public CompanyAccessRequirementHandler(ILoggedInUserService loggedInUserService, IUserSecurityRespository userSecurityRespository)
{
_loggedInUserService = loggedInUserService;
_userSecurityRespository = userSecurityRespository;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, CompanyAccessRequirement requirement)
{
if (context.User.Identity!.IsAuthenticated is false)
{
context.Fail();
return;
}
var userEmail = _loggedInUserService.UserEmail;
if (userEmail is null)
{
context.Fail();
return;
}
var user = await _userSecurityRespository.GetUser(context.User);
if (user is null)
{
context.Fail();
return;
}
var isSuperAdmin = _loggedInUserService.UserId == AppConstants.SuperAdmin.SuperUserId.ToString();
if (isSuperAdmin)
{
context.Succeed(requirement);
return;
}
var hasAccessToCompany = await _userSecurityRespository.HasAccessToCompanies(user.Id, _loggedInUserService.CompanyIds);
if (hasAccessToCompany)
{
context.Succeed(requirement);
return;
}
else
{
context.Fail();
}
}
Что делать, если я указал несколько политик в атрибуте [Authorize]
? Являются ли они ANDed или ORed ? не могу найти информацию об этом. И если они объединились, как я могу добиться поведения ИЛИ?
Его политика оценивается на And
условиях
Политики не работают, потому что у меня нет схемы аутентификации. Мой API интересует не «кто запросил», а «действителен ли данный ключ API».
хорошо, вы можете написать середину, где перехватывать http-запрос и проверять, доступен ли ключ API, или любые другие вещи, которые вам нужно проверить, если запрос действителен.
К сожалению нет. Используя средний я не могу добиться поддержки авторизации ORed:/. Кажется, я могу написать только разные типы авторизации в одном мидле или еще в чем-то. Но это некрасивый подход для меня.
Я думаю, для вашего требования должно быть три фильтра
Scheme Filter
-Проверьте правильность схемы авторизации, если она неверна, верните ошибку
BearerTokenAuthorizationFilter
-если схема "На предъявителя",если да то проверить претензии из строки ,вернуть не получится если претензии неверны
ApiKeyAuthorizationFilter
-если схема «Базовая», если да, то проверьте, что пользователь/пароль из строки возвращает ошибку, если пользователь/пароль не верны
Я пробовал, как показано ниже:
public class SchemeFilter : IAuthorizationFilter
{
private readonly string[] Schemes = new string[] { "Bearer", "Basic"};
private bool exist { get; set; }=false;
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context.HttpContext.Request.Headers.ContainsKey("Authorization"))
{
var str = context.HttpContext.Request.Headers["Authorization"].ToString();
foreach (var scheme in Schemes)
{
exist=str.StartsWith(scheme);
if (exist)
{
break;
}
}
}
if (!exist)
{
context.Result = new UnauthorizedResult();
}
}
}
public class BasicFilter : IAuthorizationFilter
{
private readonly string Scheme = "Basic";
public void OnAuthorization(AuthorizationFilterContext context)
{
var check=context.HttpContext.Request.Headers.TryGetValue("Authorization", out var value);
if ( value[0].StartsWith(Scheme))
{
var basicstr = value[0];
//modify the logical here yourself
if (basicstr != "Basic expectedbasicstr")
{
context.Result = new UnauthorizedResult();
}
}
}
}
public class BearerFilter : IAuthorizationFilter
{
private readonly string Scheme = "Bearer";
public void OnAuthorization(AuthorizationFilterContext context)
{
var check = context.HttpContext.Request.Headers.TryGetValue("Authorization", out var value);
if ( value[0].StartsWith(Scheme))
{
var bearerstr = value[0];
//modify the logical here yourself
if (bearerstr != "Bearer expectedbearerstr")
{
context.Result = new UnauthorizedResult();
}
}
}
}
Результат:
У вас может быть несколько атрибутов авторизации в вашем действии или контроллере.