Azure 应用服务中的 Swagger 身份验证

Swagger authentication in Azure App Service

在我的 Azure Mobile .NET 后端中,我想使用 Azure Mobile .NET Server Swagger 。我正在寻找从 public 访问中隐藏 swagger UI 的快速方法?有没有办法只为选定的用户提供访问权限?

首先是免责声明:即使您保护您的 Swagger UI 免受 public 消耗,您也没有保护您的 API 免受 public 消耗。您必须假设每个人都知道您的所有路由,并有适当的安全措施来保护可能进入的任何请求。

话虽这么说,但仍然没有一种简单的方法可以做到这一点。 Swashbuckle (the piece that adds Swagger to Web API) adds a custom HttpMessageHandler to the /swagger/ui route (as seen here). If you look at the Web API pipeline,你可以看到,如果你指定一个自定义处理程序,你可以绕过所有的控制器选择,Auth 过滤器等。这就是这里发生的事情。

一些解决方案:

  1. 使用应用设置仅在调试模式下有条件地调用 ConfigureSwagger(config)。这将阻止所有 /swagger 路由投入生产。或者您可以使用暂存槽并仅将其添加到那里。
  2. 你可以用这样的东西包裹 SwaggerUiHandler Basic Auth MessageHandler。如果用户转到 /swagger/ui 路线,这将提示用户输入基本信用。请参阅下面我对此代码的修改版本。

也许再考虑一下我们可以想出一个更好的解决方案——我在 Swashbuckle 存储库中看到了几个问题 (here and here),表明您不是第一个遇到这个问题的人.

修改后的 BasicAuthHandler(来自 here):

警告:最低限度测试(并确保更改验证方式 user/pass)

public class BasicAuthMessageHandler : DelegatingHandler
{
    private const string BasicAuthResponseHeader = "WWW-Authenticate";
    private const string BasicAuthResponseHeaderValue = "Basic";

    public BasicAuthMessageHandler(HttpMessageHandler innerHandler)
    {
        this.InnerHandler = innerHandler;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        AuthenticationHeaderValue authValue = request.Headers.Authorization;
        HttpResponseMessage unauthorizedResponse = request.CreateUnauthorizedResponse();

        if (authValue != null && !string.IsNullOrWhiteSpace(authValue.Parameter))
        {
            Credentials parsedCredentials = ParseAuthorizationHeader(authValue.Parameter);
            if (parsedCredentials != null)
            {
                // TODO: Check that the user/pass are valid
                if (parsedCredentials.Username == "user" &&
                    parsedCredentials.Password == "pass")
                {
                    // If match, pass along to the inner handler
                    return base.SendAsync(request, cancellationToken);
                }
            }
        }
        else
        {
            // Prompt for creds
            unauthorizedResponse.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
        }

        return Task.FromResult(unauthorizedResponse);
    }

    private Credentials ParseAuthorizationHeader(string authHeader)
    {
        string[] credentials = Encoding.ASCII.GetString(Convert
                                                        .FromBase64String(authHeader))
                                                        .Split(
                                                        new[] { ':' });
        if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0])
            || string.IsNullOrEmpty(credentials[1])) return null;
        return new Credentials()
        {
            Username = credentials[0],
            Password = credentials[1],
        };
    }
}

正在注册 Swagger 路由

// Do this after calling ConfigureSwagger
ConfigureSwagger(config);

// Remove the swagger_ui route and re-add it with the wrapped handler.
var route = config.Routes["swagger_ui"];
config.Routes.Remove("swagger_ui");
config.Routes.MapHttpRoute("swagger_ui", route.RouteTemplate, route.Defaults, route.Constraints, new BasicAuthMessageHandler(route.Handler));