我想创建一个自定义Authorize属性,以便在失败时能够发送个性化响应。有很多例子,但是我找不到我想要的东西。 注册策略时,我添加了“声明”。是否可以访问自定义属性中的已注册声明,而不必通过参数传递声明?还是可以知道是否已检查索赔,如果没有,则返回个性化答复?谢谢!
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 ...
}
答案 0 :(得分:3)
此属性采用字符串数组,在我的情况下是必需的。我需要将不同的用户角色传递给该属性,并根据一些自定义逻辑返回结果。
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()
示例是一个返回硬编码字符串的类
public class Sample : ISample
{
public string GetName() => "anish";
}
services.AddScoped(); //将ISample,Sample注册为作用域。
要异步支持,请使用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 :(得分:1)
您可以使用IAuthorizationPolicyProvider
获取保单,然后使用ClaimsAuthorizationRequirement.ClaimType
获取索赔名称。而且,由于它具有异步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));
}
}
}
}