Проверка утверждений с помощью IAuthorizationFilter - «Не удалось найти подходящий конструктор для типа» - PullRequest
1 голос
/ 28 марта 2020

Я пытаюсь проверить утверждения с реализацией IAuthorizationFilter. С помощью следующего кода он работает просто отлично -

    public class ClaimsAttribute : TypeFilterAttribute
    {
        public ClaimsAttribute(string claimType, string claimValue) : base(typeof(ClaimsFilter))
        {
            this.Arguments = new object[] { new Claim(claimType, claimValue) };
        }
    }

    public class ClaimsFilter : IAuthorizationFilter
    {
        private readonly Claim _claim;

        public ClaimsFilter(Claim claim)
        {
            _claim = claim;
        }

        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var hasClaim = context.HttpContext.User.Claims.Any(p => p.Type == _claim.Type && p.Value == _claim.Value);
            if (!hasClaim)
            {
                context.Result = new ForbidResult();
            }
        }
    }

    public class DocumentController : Controller
    {
        [Claims(AppClaimTypes.Permission, "CanReadDocument")]
        [HttpGet]
        public ActionResult GetDocument()
        {
            return View();
        }
    }

Так что я подумал, что я мог бы также проверить наличие нескольких значений Claim -

    public class Claims2Attribute : TypeFilterAttribute
    {
        public Claims2Attribute(string claimType, params string[] claimValues) : base(typeof(Claims2Filter))
        {
            this.Arguments = new object[claimValues.Length];
            for (int i = 0; i < claimValues.Length; i++)
            {
                this.Arguments[i] = new Claim(claimType, claimValues[i]);
            }
        }
    }

    public class Claims2Filter : IAuthorizationFilter
    {
        private readonly Claim[] _claims;

        public Claims2Filter(Claim[] claims)
        {
            _claims = claims;
        }

        public void OnAuthorization(AuthorizationFilterContext context)
        {
            bool hasClaim = false;
            foreach (var item in _claims)
            {
                hasClaim = context.HttpContext.User.Claims.Any(p => p.Type == item.Type && p.Value == item.Value);
                if (hasClaim)
                    break;
            }

            if (!hasClaim)
            {
                context.Result = new ForbidResult();
            }
        }
    }

    public class DocumentController : Controller
    {
        [Claims2(AppClaimTypes.Permission, "CanReadSecretDocument", "SecretAccess")]
        [HttpGet]
        public ActionResult GetSecretDocument()
        {
            return View();
        }
    }

Но теперь выдает ошибку -

InvalidOperationException: не найден подходящий конструктор для типа AuthorizationFilterTest.Claims2Filter. Убедитесь, что тип конкретный, и службы зарегистрированы для всех параметров конструктора publi * 1017. *.

Я не думаю, что это что-то связанное с регистрацией служб, иначе первая версия не будет работать. Это кажется чем-то более тривиальным / глупым, но я не могу его найти.

Что я делаю не так?

1 Ответ

0 голосов
/ 29 марта 2020

Это примерно , как передаются аргументы для создания экземпляра целевого типа IAuthorization (в данном случае Claims2Filter).

Если свойство Arguments (которое является массивом) объекта) содержит несколько элементов, тогда каждый элемент считается отдельным аргументом для передачи отдельному параметру конструктора целевого IAuthorization типа. Другими словами, требуется взаимно-однозначное сопоставление между количеством элементов в Argument и числом параметра конструктора.

Таким образом, когда Arguments содержит два объекта Claim, среда выполнения фактически ожидая, что Claims2Filter будет иметь следующий конструктор -

    public ClaimsFilter(Claim claim1, Claim claim2)
    {
            //
    }

Чтобы использовать конструктор (типа IAuthorization), который принимает один параметр, который является массивом объекта Claim, свойство Arguments (типа TypeFilterAttribute) должен содержать один элемент, который является массивом объекта Claim.

Итак, следующее изменение заставляет все работать как положено -

    public class Claims2Attribute : TypeFilterAttribute
    {
        public Claims2Attribute(string claimType, params string[] claimValues) : base(typeof(Claims2Filter))
        {
            var claims = new Claim[claimValues.Length];
            for (int i = 0; i < claimValues.Length; i++)
            {
                claims[i] = new Claim(claimType, claimValues[i]);
            }

            this.Arguments = new object[] { claims };
        }
    }

Я надеюсь, что объяснение достаточно ясно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...