我正在寻找一种方法来确定端点是否需要使用IOperationFilter进行授权(.Net Core3.1)。
如果授权是通过筛选器或显式设置为属性的,则可以在OperationFilterContext context.ApiDescription.ActionDescriptor.FilterDescriptors.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter)和context.ApiDescription.CustomAttributes().OfType<AuthorizeAttribute>()中找到它。
但是,如果授权设置为endpoints.MapControllers().RequireAuthorization();,则它既不会出现在筛选器中,也不会出现在属性中,这应该会将AuthorizationAttribute添加到所有端点。如果在这种情况下将auth应用于端点,您对如何捕获有什么想法吗?
发布于 2021-03-10 01:50:30
phwew,我今天能够像这样击败它(swashbuckle 5.63):
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Authorization;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace YourNameSpace
{
public class SwaggerGlobalAuthFilter : IOperationFilter
{
public void Apply( OpenApiOperation operation, OperationFilterContext context )
{
context.ApiDescription.TryGetMethodInfo( out MethodInfo methodInfo );
if ( methodInfo == null )
{
return;
}
var hasAllowAnonymousAttribute = false;
if ( methodInfo.MemberType == MemberTypes.Method )
{
// NOTE: Check the controller or the method itself has AllowAnonymousAttribute attribute
hasAllowAnonymousAttribute =
methodInfo.DeclaringType.GetCustomAttributes( true ).OfType<AllowAnonymousAttribute>().Any() ||
methodInfo.GetCustomAttributes( true ).OfType<AllowAnonymousAttribute>().Any();
}
if ( hasAllowAnonymousAttribute )
{
return;
}
// NOTE: This adds the "Padlock" icon to the endpoint in swagger,
// we can also pass through the names of the policies in the List<string>()
// which will indicate which permission you require.
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2" // note this 'Id' matches the name 'oauth2' defined in the swagger extensions config section below
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
}
}
};
}
}
}在swagger配置扩展中
options.AddSecurityDefinition( "oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow
{
//_swaggerSettings is a custom settings object of our own
AuthorizationUrl = new Uri( _swaggerSettings.AuthorizationUrl ),
Scopes = _swaggerSettings.Scopes
}
}
} );
options.OperationFilter<SwaggerGlobalAuthFilter>();由文档、其他SO和反编译的内置SecurityRequirementsOperationFilter代码组合而成
afaik,它正在为所有路由的端点定义全局身份验证设置,控制器或端点上显式具有AllowAnonymousAttribute的端点除外。正如您最初的问题所暗示的那样,在设置路由时使用扩展RequireAuthorization()隐式地将该属性放在所有端点上,并且检测到Authorize属性的内置SecurityRequirementsOperationFilter无法获取该属性。由于您的路由设置实际上是将Authorize放在每个控制器/路由上,因此,似乎像这样设置一个排除AllowAnonymous的默认全局过滤器将与您在管道中配置的内容保持一致。
我怀疑可能有一种更“内置”的方式来做这件事,但我找不到它。
发布于 2022-01-10 14:35:47
显然,这在NSwag repo上也是一个开放的问题(对于像我这样的人来说,他们也有同样的问题,但使用的是NSwag,而不是Swashbuckle):
https://github.com/RicoSuter/NSwag/issues/2817
这里还有另一个解决问题的例子(不仅是安全需求,还有它的范围)。
发布于 2022-02-14 16:42:13
我知道这个问题已经有很长一段时间了。
但我也面临着类似的问题,根据GitHub here中的一个问题的建议,我设法使用IOperationFilter的这个实现解决了这个问题(现在工作得很棒):
public class AuthorizeCheckOperationFilter : IOperationFilter
{
private readonly EndpointDataSource _endpointDataSource;
public AuthorizeCheckOperationFilter(EndpointDataSource endpointDataSource)
{
_endpointDataSource = endpointDataSource;
}
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var descriptor = _endpointDataSource.Endpoints.FirstOrDefault(x =>
x.Metadata.GetMetadata<ControllerActionDescriptor>() == context.ApiDescription.ActionDescriptor);
var hasAuthorize = descriptor.Metadata.GetMetadata<AuthorizeAttribute>()!=null;
var allowAnon = descriptor.Metadata.GetMetadata<AllowAnonymousAttribute>() != null;
if (!hasAuthorize || allowAnon) return;
operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" });
operation.Security = new List<OpenApiSecurityRequirement>
{
new()
{
[
new OpenApiSecurityScheme {Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2"}
}
] = new[] {"api1"}
}
};
}
}这期杂志这样写道:
ControllerActionDescriptor.EndpointMetadata仅反映在控制器操作上发现的元数据。通过端点API配置的任何元数据都不会在此处显示。这主要是我们将其记录为基础架构的原因-只是因为它使用起来有点混乱。
您可以使用以下几个选项
a)你可以使用Authorize来装饰你的控制器。这应该允许元数据显示在属性中。
b)您可以通过读取EndpointDataSource来查找元数据。
https://stackoverflow.com/questions/62432556
复制相似问题