Swashbuckle.webapi: How to hide swagger functionality from certain users

Created on 12 Jan 2016  路  14Comments  路  Source: domaindrivendev/Swashbuckle.WebApi

I am using Swashbuckle for our API which has different levels of users (Our internal team and third party external developers).

How can I hide methods in the Swashbuckle UI from the third party developers but allow our internal team to still view and run all of the admin only methods?

waiting for response

Most helpful comment

@jmmunger That's what computer science is all about, pain pain and more pain!

All 14 comments

Similar to this I want a feature to turn the swagger off for Production preferably through web.config?

+1

See #602 for enabling via web.config.

Restricting access to certain users is not something that's supported out-of-the-box. To do this, I would recommend injecting a DelegatingHandler (see http://www.asp.net/web-api/overview/advanced/http-message-handlers) into your WebApi pipeline. If the requested path starts with "/swagger" then it should check for an authenticated session and return a 401/403 if access is not allowed, otherwise it can just delegate to the next handler in the chain.

After a little more research, it turns out the easiest way to accomplish this is by wiring up a Document Filter (see readme) that removes certain operations from the Swagger Document according to the current identity. Here's a simple example, successfully tested with "Forms Authentication", that hides all the "write" operations for non-authenticated viewers:

public class SwaggerAccessDocumentFilter : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
    {
        if (!Thread.CurrentPrincipal.Identity.IsAuthenticated)
        {
            foreach (var pathItem in swaggerDoc.paths.Values)
            {
                pathItem.delete = null;
                pathItem.patch = null;
                pathItem.post = null;
                pathItem.put = null;
            }
        }
    }
}

If you wanted to take things a step further and hide operations according to the actual authorization rules that are applied to your actions with the "AuthorizeAttribute" filter, you can use a combination of an Operation Filter (see readme), which adds additional metadata, and a subsequent Document Filter that uses that metadata to show/hide operations:

Here's the Operation Filter:

public class SwaggerAccessOperationFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        var authorizeAttributes = apiDescription.ActionDescriptor.GetFilterPipeline()
            .Select(filterInfo => filterInfo.Instance)
            .OfType<AuthorizeAttribute>();

        operation.vendorExtensions.Add("x-restricted", authorizeAttributes.Any());
    }
}

And the Document Filter:

public class SwaggerAccessDocumentFilter : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
    {
        if (!Thread.CurrentPrincipal.Identity.IsAuthenticated)
        {
            foreach (var pathItem in swaggerDoc.paths.Values)
            {
                pathItem.delete = NullifyIfRestricted(pathItem.delete);
                pathItem.get = NullifyIfRestricted(pathItem.get);
                pathItem.head = NullifyIfRestricted(pathItem.head);
                pathItem.options = NullifyIfRestricted(pathItem.options);
                pathItem.patch = NullifyIfRestricted(pathItem.patch);
                pathItem.post = NullifyIfRestricted(pathItem.post);
                pathItem.put = NullifyIfRestricted(pathItem.put);
            }
        }
    }

    private Operation NullifyIfRestricted(Operation operation)
    {
        if (operation == null || (bool)operation.vendorExtensions["x-restricted"] == true)
            return null;

        return operation;
    }
}

Great thanks

I have tried using the delgate handler and the operation and document filter for protecting the methods that is not supposed to be displayed for the user.

But, how can we configure the Swagger UI to protect it and ask for the Login as soon as the user try to access the swagger ui page.

We use OAuth 2.0

Any help is really appreciated

Setting null the Path items works very well but the return and parameters types still appear in the schema.

Which I do know know how to remove, This is frustrating since they are present in the swaggerDoc.definition in the Apply of the documentFilter. I just dont know which are used and which are not

@jmmunger Have you tried posting your question on Stackoverflow?

Yes I did. Unfortunately no one responded.

But fortunately for me I figured out the answer.

But the answer has been a pain to obtain.

here is a link for the Question on stack overflow if it can help people
https://stackoverflow.com/questions/46116507/swashbuckle-hide-unreferenced-model/46122090#46122090

@jmmunger That's what computer science is all about, pain pain and more pain!

@jmmunger I'd just like to say thanks for following up on this, your response on stack overflow has been very helpful. I am attempting to filter the available endpoints based on the method starting letter as a form of pagination because Swagger is taking several minutes to load and render with the number of endpoints I have, and I think I have a good understanding of how to do this now. Thanks again!

@vanderstack I'm interested on your case!
I've been optimizing the generation of the Swagger Doc, I have some questions:

  • How many endpoints do you have?
  • How big (KB) is your final swagger doc?
  • Do you have any large classes (hundred of fields or properties)?
  • Can you share your code on GitHub?

@domaindrivendev How can I access Thread.CurrentPrincipal.Identity.IsAuthenticated in .NET Core?

@froston in .NET Core you need to use the HttpContext.User.Identity.IsAuthenticated property when you have access to the HttpContext (i.e. you are within an Controller or ApiController). You can also access the HttpContext via injecting a IHttpContextAccessor into a class - but it is not recommended unless you absolutely need it for backwards compatibility. The only reason that IHttpContextAccessor is available at all is because of backwards compatibility - see Access HttpContext in ASP.NET Core

Was this page helpful?
0 / 5 - 0 ratings