asp.net core mvc 3.1 源码分析(四)

AuthorizationApplicationModelProvider

该类主要添加授权认证的过滤器

先在Controller和Action中找到实现IAuthorizeData的特性,再根据IAuthorizeData创建AuthorizeFilter过滤器,把AuthorizeFilter添加到Controller和Action的Filters列表中

具体的授权逻辑后面分开讲

internal class AuthorizationApplicationModelProvider : IApplicationModelProvider
    {
        private readonly MvcOptions _mvcOptions;
        private readonly IAuthorizationPolicyProvider _policyProvider;

        public AuthorizationApplicationModelProvider(
            IAuthorizationPolicyProvider policyProvider,
            IOptions<MvcOptions> mvcOptions)
        {
            _policyProvider = policyProvider;
            _mvcOptions = mvcOptions.Value;
        }

        public int Order => -1000 + 10;

        public void OnProvidersExecuted(ApplicationModelProviderContext context)
        {
            // Intentionally empty.
        }

        public void OnProvidersExecuting(ApplicationModelProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (_mvcOptions.EnableEndpointRouting)
            {
                // When using endpoint routing, the AuthorizationMiddleware does the work that Auth filters would otherwise perform.
                // Consequently we do not need to convert authorization attributes to filters.
                return;
            }

            foreach (var controllerModel in context.Result.Controllers)
            {
                var controllerModelAuthData = controllerModel.Attributes.OfType<IAuthorizeData>().ToArray();
                if (controllerModelAuthData.Length > 0)
                {
                    controllerModel.Filters.Add(GetFilter(_policyProvider, controllerModelAuthData));
                }
                foreach (var attribute in controllerModel.Attributes.OfType<IAllowAnonymous>())
                {
                    controllerModel.Filters.Add(new AllowAnonymousFilter());
                }

                foreach (var actionModel in controllerModel.Actions)
                {
                    var actionModelAuthData = actionModel.Attributes.OfType<IAuthorizeData>().ToArray();
                    if (actionModelAuthData.Length > 0)
                    {
                        actionModel.Filters.Add(GetFilter(_policyProvider, actionModelAuthData));
                    }

                    foreach (var attribute in actionModel.Attributes.OfType<IAllowAnonymous>())
                    {
                        actionModel.Filters.Add(new AllowAnonymousFilter());
                    }
                }
            }
        }

        public static AuthorizeFilter GetFilter(IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizeData> authData)
        {
            // The default policy provider will make the same policy for given input, so make it only once.
            // This will always execute synchronously.
            if (policyProvider.GetType() == typeof(DefaultAuthorizationPolicyProvider))
            {
                var policy = AuthorizationPolicy.CombineAsync(policyProvider, authData).GetAwaiter().GetResult();
                return new AuthorizeFilter(policy);
            }
            else
            {
                return new AuthorizeFilter(policyProvider, authData);
            }
        }
    }

 

ApiBehaviorApplicationModelProvider

internal class ApiBehaviorApplicationModelProvider : IApplicationModelProvider
    {
        public ApiBehaviorApplicationModelProvider(
            IOptions<ApiBehaviorOptions> apiBehaviorOptions,
            IModelMetadataProvider modelMetadataProvider,
            IClientErrorFactory clientErrorFactory,
            ILoggerFactory loggerFactory)
        {
            var options = apiBehaviorOptions.Value;

            ActionModelConventions = new List<IActionModelConvention>()
            {
                new ApiVisibilityConvention(),
            };

            if (!options.SuppressMapClientErrors)
            {
                ActionModelConventions.Add(new ClientErrorResultFilterConvention());
            }

            if (!options.SuppressModelStateInvalidFilter)
            {
                ActionModelConventions.Add(new InvalidModelStateFilterConvention());
            }

            if (!options.SuppressConsumesConstraintForFormFileParameters)
            {
                ActionModelConventions.Add(new ConsumesConstraintForFormFileParameterConvention());
            }

            var defaultErrorType = options.SuppressMapClientErrors ? typeof(void) : typeof(ProblemDetails);
            var defaultErrorTypeAttribute = new ProducesErrorResponseTypeAttribute(defaultErrorType);
            ActionModelConventions.Add(new ApiConventionApplicationModelConvention(defaultErrorTypeAttribute));

            if (!options.SuppressInferBindingSourcesForParameters)
            {
                ActionModelConventions.Add(new InferParameterBindingInfoConvention(modelMetadataProvider));
            }
        }

        /// <remarks>
        /// Order is set to execute after the <see cref="DefaultApplicationModelProvider"/> and allow any other user
        /// <see cref="IApplicationModelProvider"/> that configure routing to execute.
        /// </remarks>
        public int Order => -1000 + 100;

        public List<IActionModelConvention> ActionModelConventions { get; }

        public void OnProvidersExecuted(ApplicationModelProviderContext context)
        {
        }

        public void OnProvidersExecuting(ApplicationModelProviderContext context)
        {
            foreach (var controller in context.Result.Controllers)
            {
                if (!IsApiController(controller))
                {
                    continue;
                }

                foreach (var action in controller.Actions)
                {
                    // Ensure ApiController is set up correctly
                    EnsureActionIsAttributeRouted(action);

                    foreach (var convention in ActionModelConventions)
                    {
                        convention.Apply(action);
                    }
                }
            }
        }

        private static void EnsureActionIsAttributeRouted(ActionModel actionModel)
        {
            if (!IsAttributeRouted(actionModel.Controller.Selectors) &&
                !IsAttributeRouted(actionModel.Selectors))
            {
                // Require attribute routing with controllers annotated with ApiControllerAttribute
                var message = Resources.FormatApiController_AttributeRouteRequired(
                     actionModel.DisplayName,
                    nameof(ApiControllerAttribute));
                throw new InvalidOperationException(message);
            }

            bool IsAttributeRouted(IList<SelectorModel> selectorModel)
            {
                for (var i = 0; i < selectorModel.Count; i++)
                {
                    if (selectorModel[i].AttributeRouteModel != null)
                    {
                        return true;
                    }
                }

                return false;
            }
        }

        private static bool IsApiController(ControllerModel controller)
        {
            if (controller.Attributes.OfType<IApiBehaviorMetadata>().Any())
            {
                return true;
            }

            var controllerAssembly = controller.ControllerType.Assembly;
            var assemblyAttributes = controllerAssembly.GetCustomAttributes();
            return assemblyAttributes.OfType<IApiBehaviorMetadata>().Any();
        }
    }

该类涉及到webapi方面

 

 对ActionModel设置相关的属性和过滤器

 

posted @ 2020-04-06 16:44  蓝平凡  阅读(401)  评论(0编辑  收藏  举报