asp.net-web-api - 如何在 ASP.Net Core (WebAPI) 中基于 HTTP 动词和其他属性以声明方式指定授权策略

标签 asp.net-web-api asp.net-authorization

我注册了几个授权策略:

ConfigureServices()
{
    services.AddAuthorization(authorisationOptions =>
    {
        authorisationOptions.AddPolicy(StandardAuthorizationPolicy.Name, StandardAuthorizationPolicy.Value);
        authorisationOptions.AddPolicy(MutatingActionAuthorizationPolicy.Name, MutatingActionAuthorizationPolicy.Value);
    }); 
}

然后我在所有端点上设置默认授权策略:

Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseEndpoints(endpoints =>
    {
        endpoints
            .MapControllers()
            .RequireAuthorization(StandardAuthorizationPolicy.Name); // Declaratively require the standard authorization policy on all controller endpoints
    });
}

在我想要指定变异策略的端点上,我当前执行以下操作:

[HttpPut]
[Authorize(MutatingActionAuthorizationPolicy.Name)] // Because 'PUT'. NOT DECLARATIVE! :-(
public async Task<IActionResult> AddOrUpdateOverride(SourceOverride sourceOverride, CancellationToken cancellationToken)
{
  // ..
}

我真正想要的是更多的控制权,以声明方式应用基于 HttpVerb 的变异策略(即 POST、PUT、PATCH、DELETE)。

关于如何实现这一目标有什么想法吗?允许我在 Controller 方法/类上使用其他属性的奖励积分,而不仅仅是 [HttpPost] 等。

注意:我见过一些涉及转换内容的解决方案(并且似乎围绕单一访问策略)。我真的宁愿坚持多种访问策略。

如果我遇到困难,我可能最终会为其编写一个约定测试。

最佳答案

您可以实现自定义 RequireAuthorization 扩展,该扩展将 HTTP 谓词过滤函数作为参数,并检查 HttpMethodAttribute 的每个端点元数据

public static class AuthorizationEndpointConventionBuilderExtensions
    {
        /// <summary>
        /// Adds authorization policies with the specified <see cref="IAuthorizeData"/> to the endpoint(s) filtered by supplied filter function
        /// </summary>
        /// <param name="builder">The endpoint convention builder.</param>
        /// <param name="filterOnHttpMethods">Filters http methods that we applying specific policies to</param>
        /// <param name="authorizeData">
        /// A collection of <paramref name="authorizeData"/>. If empty, the default authorization policy will be used.
        /// </param>
        /// <returns>The original convention builder parameter.</returns>
        public static TBuilder RequireAuthorizationForHttpMethods<TBuilder>(this TBuilder builder, Func<IEnumerable<HttpMethod>, bool> filterOnHttpMethods, params IAuthorizeData[] authorizeData)
            where TBuilder : IEndpointConventionBuilder
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (authorizeData == null)
            {
                throw new ArgumentNullException(nameof(authorizeData));
            }

            if (authorizeData.Length == 0)
            {
                authorizeData = new IAuthorizeData[] { new AuthorizeAttribute(), };
            }

            builder.Add(endpointBuilder =>
            {
                var appliedHttpMethodAttributes = endpointBuilder.Metadata
                .Where(x => x is HttpMethodAttribute)
                .Cast<HttpMethodAttribute>();

                if (appliedHttpMethodAttributes.Any(x => filterOnHttpMethods(x.HttpMethods
                                              .Select(method => new HttpMethod(method)))))
                {
                    foreach (var data in authorizeData)
                    {
                        endpointBuilder.Metadata.Add(data);
                    }
                }
            });
            return builder;
        }

        /// <summary>
        /// Adds authorization policies with the specified names to the endpoint(s) for filtered endpoints that return for filterOnHttpMethod
        /// </summary>
        /// <param name="builder">The endpoint convention builder.</param>
        /// <param name="filterOnHttpMethods">Filters http methods that we applying specific policies to</param>
        /// <param name="policyNames">A collection of policy names. If empty, the default authorization policy will be used.</param>
        /// <returns>The original convention builder parameter.</returns>
        public static TBuilder RequireAuthorizationForHttpMethods<TBuilder>(this TBuilder builder, Func<IEnumerable<HttpMethod>, bool> filterOnHttpMethods, params string[] policyNames)
        where TBuilder : IEndpointConventionBuilder
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (policyNames == null)
            {
                throw new ArgumentNullException(nameof(policyNames));
            }

            return builder.RequireAuthorizationForHttpMethods(filterOnHttpMethods, policyNames.Select(n => new AuthorizeAttribute(n)).ToArray());
        }
    }

然后在原始扩展旁边使用此扩展:

        app.UseEndpoints(endpoints =>
        {
            var mutatingHttpMethods = new HashSet<HttpMethod>()
            {
                HttpMethod.Post,
                HttpMethod.Put,
                HttpMethod.Delete
            };

            endpoints
                .MapControllers()
                .RequireAuthorization(StandardAuthorizationPolicy.Name)
                .RequireAuthorizationForHttpMethods(httpMethods => 
                 httpMethods.Any(httpMethod => mutatingHttpMethods.Contains(httpMethod)), 
                 MutatingActionAuthorizationPolicy.Name);
            });
        }


关于asp.net-web-api - 如何在 ASP.Net Core (WebAPI) 中基于 HTTP 动词和其他属性以声明方式指定授权策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66536509/

相关文章:

c# - 匿名用户授权(自动认证)

c# - Web API 中的内存缓存

javascript - 我似乎无法发布一系列对象

c# - 音频的Base64验证

asp.net-mvc - 如何从 Forms Authentication 迁移到 ASP .NET Identity

c# - 使用 CookieAuthenticationProvider 调用 AuthenticationManager.SignIn() 后 ClaimsIdentity 信息存储在哪里

node.js - 使用 SendGrid 发送的电子邮件内容中的随机空格

asp.net-web-api - WebAPI 路由协助

asp.net-mvc - 如何锁定 ASP.NET MVC 中的路径?

c# - ASP.Net Core 的自定义不记名 token 授权