【问题标题】:Global Authorize filter not working with Swagger UI Asp.net Web Api全局授权过滤器不适用于 Swagger UI Asp.net Web Api
【发布时间】:2019-10-17 09:05:46
【问题描述】:

我正在用我的 Asp.net WEB Api 项目实现Swagger UI,我使用默认的System.Web.Http.AuthorizeAttribute,我已在Register 方法中的WebApiConfig.cs 中将其注册为

 config.Filters.Add(new AuthorizeAttribute());

我已将 Swagger UI 实现为

public static void Register()
{
 var thisAssembly = typeof(SwaggerConfig).Assembly;

 GlobalConfiguration.Configuration
 .EnableSwagger(c =>
 {
    c.SingleApiVersion("v1", "COE.Services.WebAPI");

    c.OAuth2("oauth2")
    .Description("OAuth2 Implicit Grant")
    .Flow("implicit")
    .AuthorizationUrl(configurationService.BaseWithTokenUrl)
    .Scopes(scopes =>
    {
        scopes.Add("user_scope", "Access REST API");
    });

    c.OperationFilter<AssignOAuth2SecurityRequirements>();
})
.EnableSwaggerUi(c =>
{
    c.EnableOAuth2Support("COEApi", configurationService.BaseUrl + "swagger/ui/o2c-html", "Swagger");
});
}     

 public class AssignOAuth2SecurityRequirements : IOperationFilter
 {
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        var toBeAuthorize = apiDescription.GetControllerAndActionAttributes<AuthorizeAttribute>().Any();
        var allowAnonymous = apiDescription.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();

        if (toBeAuthorize && !allowAnonymous)
        {
            if (operation.parameters == null)
                operation.parameters = new List<Parameter>();

            operation.parameters.Add(new Parameter()
            {
                name = "Authorization",
                @in = "header",
                description = "Bearer <token>",
                required = true,
                type = "string"
            });
        }
    }
}

我也尝试在Swashbuckle's Git hub repository 上搜索解决方案,但找不到任何解决方案。

我也遇到过opened issue about this on Github

【问题讨论】:

    标签: asp.net-web-api authorization swagger-ui swashbuckle


    【解决方案1】:

    Swagger API 和 Swashbuckle 中的 UI 是 implementedHttpMessageHandler 用于路由。所以过滤器在那里不起作用(因为它们仅适用于 ASP.NET WebAPI 的控制器和操作)。

    但是,您可以以不同的方式防止未经授权访问 swagger。如果您使用 ASP.NET Web API 作为 Owin 中间件(通过使用 Microsoft.AspNet.WebApi.Owin nuget 包),那么您可以编写简单的中间件并将其放在 swagger 中间件之前以拒绝对“swagger/docs/”和“swagger/ui/”的请求(Swagger API 和 UI 的默认路由)。

    例如:

    [assembly: OwinStartupAttribute(typeof(WebApplicationMvcWebApiSwagger.Startup))]
    namespace WebApplicationMvcWebApiSwagger
    {
        public partial class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                ConfigureAuth(app);
    
                app.UseRejectUnathorizedUsersForSwagger();
    
                var config = new HttpConfiguration();
    
                config
                    .EnableSwagger(c =>
                    {
                        c.SingleApiVersion("v1", "A title for your API");
                    })
                    .EnableSwaggerUi();
    
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
                app.UseWebApi(config);
            }
        }
    
        public static class SwaggerAuthorizationMiddleware
        {
            public static void UseRejectUnathorizedUsersForSwagger(this IAppBuilder appBuilder)
            {
                appBuilder.Use((context, next) =>
                {
                    if (context.Request.Path.Value.StartsWith("/swagger/docs/")
                        || context.Request.Path.Value.StartsWith("/swagger/ui/"))
                    {
                        var user = (context.Request.User as ClaimsPrincipal);
                        if (user == null || !user.Identity.IsAuthenticated)
                        {
                            context.Response.StatusCode = 401;
                            context.Response.ContentType = "text/plain";
                            return context.Response.WriteAsync("Unauthorized. Log in to use swagger.");
                        }
                    }
    
                    return next.Invoke();
                });
            }
        }
    }
    

    ConfigureAuth(app) 是负责身份验证的中间件(此处由使用 ASP.NET Identity 的 Visual Studio 模板生成)。在 auth 中间件之后和 WebApi 中间件之前(也添加了 swagger),您可以使用自定义身份验证逻辑放置自己的中间件。

    如果您不将 Owin 用于 ASP.NET API,那么您可以尝试实现 HttpMessageHandler 并在其中添加与之前 OWIN 中间件示例类似的逻辑。您应该能够使用Thread.CurrentPrincipal 来获取授权数据(或者在 IIS 中托管时使用HttpContext.Current.User?我不确定):

    protected void Application_Start()
    {
        //...
        GlobalConfiguration.Configure(WebApiConfig.Register);
        //...
    }
    
    config.MessageHandlers.Add(new RequireAdminUserForSwaggerDocAndUiHandler());
    
    config
        .EnableSwagger(c =>
        {
            c.SingleApiVersion("v1", "A title for your API");
        })
        .EnableSwaggerUi();
    
    config.MapHttpAttributeRoutes();
    
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
    
    public class RequireAdminUserForSwaggerDocAndUiHandler : DelegatingHandler
    {
        async protected override Task<HttpResponseMessage> SendAsync(
                HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request.RequestUri.PathAndQuery.StartsWith("/swagger/docs/")
                || request.RequestUri.PathAndQuery.StartsWith("/swagger/ui/"))
            {
                if (Thread.CurrentPrincipal == null || !Thread.CurrentPrincipal.Identity.IsAuthenticated)
                {
                    var response = new HttpResponseMessage();
                    response.StatusCode = System.Net.HttpStatusCode.Unauthorized;
                    response.Content = new StringContent("Unauthorized. Log in to use swagger.");
                    return response;
                }
            }
    
            return await base.SendAsync(request, cancellationToken);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-07-18
      • 1970-01-01
      • 1970-01-01
      • 2012-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-06
      • 2021-10-07
      相关资源
      最近更新 更多