#c# #asp.net-core
#c# #asp.net-core
Вопрос:
Я хочу создать пользовательский атрибут авторизации, чтобы иметь возможность отправлять персонализированный ответ в случае сбоя. Есть много примеров, но я не смог найти то, что я ищу. При регистрации политики я добавляю «утверждение». Возможно ли получить доступ к этому зарегистрированному утверждению в пользовательском атрибуте без необходимости передавать утверждение по параметру? или возможно узнать, произошла ли проверка утверждения, и если нет, вернуть персонализированный ответ? Спасибо!
public static void AddCustomAuthorization(this IServiceCollection serviceCollection)
{
serviceCollection.AddAuthorization(x =>
{
x.AddPolicy(UserPolicy.Read,
currentPolicy => currentPolicy.RequireClaim(UserClaims.Read));
});
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext authorizationFilterContext)
{
if (authorizationFilterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (!authorizationFilterContext.HttpContext.User.HasClaim(x => x.Value == "CLAIM_NAME")) // ACCESS TO REGISTER CLAIM => currentPolicy => currentPolicy.RequireClaim(UserClaims.Read)
{
authorizationFilterContext.Result = new ObjectResult(new ApiResponse(HttpStatusCode.Unauthorized));
}
}
}
}
[HttpGet]
[CustomAuthorizeAttribute(Policy = UserPolicy.Read)]
public async Task<IEnumerable<UserDTO>> Get()
{
return ...
}
Комментарии:
1. вы должны иметь возможность получить доступ к утверждению из метода OnAuthorization
Ответ №1:
Вы можете использовать IAuthorizationPolicyProvider
для получения политики, а затем использовать ClaimsAuthorizationRequirement.ClaimType
для получения имени утверждения. И поскольку у него есть async API, его лучше использовать IAsyncAuthorizationFilter
вместо IAuthorizationFilter
. Попробуйте это:
public class CustomAuthorizeAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
{
public async Task OnAuthorizationAsync(AuthorizationFilterContext authorizationFilterContext)
{
var policyProvider = authorizationFilterContext.HttpContext
.RequestServices.GetService<IAuthorizationPolicyProvider>();
var policy = await policyProvider.GetPolicyAsync(UserPolicy.Read);
var requirement = (ClaimsAuthorizationRequirement)policy.Requirements
.First(r => r.GetType() == typeof(ClaimsAuthorizationRequirement));
if (authorizationFilterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (!authorizationFilterContext.HttpContext
.User.HasClaim(x => x.Value == requirement.ClaimType))
{
authorizationFilterContext.Result =
new ObjectResult(new ApiResponse(HttpStatusCode.Unauthorized));
}
}
}
}
Комментарии:
1. Привет @AlbertK. Спасибо за ответ. Он мне очень помог. Мне пришлось изменить только 3 строки кода. 1) authorizationFilterContext.HttpContext.RequestServices. GetRequiredService <IAuthorizationPolicyProvider>() 2) Политика авторизации. Требования. OfType<ClaimsAuthorizationRequirement>(). FirstOrDefault() 3) policyProvider. GetPolicyAsync(политика)
Ответ №2:
Этот атрибут принимает массив строк, который был необходим в моем случае. Мне нужно было передать роли разных пользователей этому атрибуту и вернуть результат на основе некоторой пользовательской логики.
public class CustomAuthFilter : AuthorizeAttribute, IAuthorizationFilter
{
public CustomAuthFilter(params string[] args)
{
Args = args;
}
public string[] Args { get; }
public void OnAuthorization(AuthorizationFilterContext context)
{
//Custom code ...
//Resolving a custom Services from the container
var service = context.HttpContext.RequestServices.GetRequiredService<ISample>();
string name = service.GetName(); // returns "anish"
//Return based on logic
context.Result = new UnauthorizedResult();
}
}
Вы можете украсить свой контроллер этим атрибутом, как показано ниже
[CustomAuthFilter("Anish","jiya","sample")]
public async Task<IActionResult> Index()
Sample — это класс, который возвращает жестко закодированную строку
public class Sample : ISample
{
public string GetName() => "anish";
}
Услуги.AddScoped(); //Register является примером, образец как ограниченный.
ДЛЯ АСИНХРОННОЙ ПОДДЕРЖКИ используйте IAsyncAuthorizationFilter
public class CustomAuthFilter : AuthorizeAttribute, IAsyncAuthorizationFilter
{
public CustomAuthFilter(params string[] args)
{
Args = args;
}
public string[] Args { get; }
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
//DO Whatever...
//Resolve Services from the container
var service = context.HttpContext.RequestServices.GetRequiredService<ISample>();
var httpClientFactory = context.HttpContext.RequestServices.GetRequiredService<IHttpClientFactory>();
string name = service.GetName();
using var httpClient = httpClientFactory.CreateClient();
var resp = await httpClient.GetAsync("https://jsonplaceholder.typicode.com/todos/1");
var data = await resp.Content.ReadAsStringAsync();
//Return based on logic
context.Result = new UnauthorizedResult();
}
}
Надеюсь, это поможет..
Комментарии:
1. Спасибо за совет по использованию
IAsyncAuthorizationFilter
поддерживаемого метода Async (например, внешние вызовы для проверки будут асинхронными).