启用Swashbuckle(Swagger文档)中的承载令牌。

50

我创建了一个使用个人账户安全的asp.net webapi应用程序,这样Bearer令牌就默认启用了。它能够正常工作,以至于我可以在Postman中测试它们而没有问题。

现在问题出现了,当我尝试通过Swashbuckle集成Swagger UI时。我执行了以下操作:

Install-Package Swashbuckle

然后更改了SwaggerConfig.cs文件:

GlobalConfiguration.Configuration
    .EnableSwagger(c =>
    {
        c.ApiKey("Token")
            .Description("Filling bearer token here")
            .Name("Authorization")
            .In("header");
    })
    .EnableSwaggerUi(c =>
    {
        c.EnableApiKeySupport("Authorization", "header");
    });

启动我的应用程序,填写 Bearer Token:

enter image description here

但是当我运行需要授权的 API 请求时,它没有起作用。以下是屏幕截图:

enter image description here

Bearer Token 已经添加到头部的 Authorization 中。但我仍然收到错误代码 401。我在想这是否是因为 Token 被编码了(空格被替换为 %20)?有什么想法吗?谢谢。

顺便问一下,我想知道如何将/token 添加到我的 Swagger 文档中,以便我可以在 Swagger UI 中获取 Token。


我确认编码的空格(%20)是原因。但是我该如何用空格替换%20? - Bagusflyer
1
好奇:EnableApiKeySupport() 方法定义在哪里?我正在使用最新的 Swashbuckle(v5.4.0),但我没有看到它...? - urig
找到了。这是SwaggeruiConfig的一个方法,应该在c.EnableSwaggerUi()中设置。 - urig
4个回答

21

更新

下面所详述的问题现在已经在Swashbuckle v5.5.0中得到解决。

问题

我刚遇到了完全相同的问题。我认为根本原因在于Swashbuckle源代码的这行代码:

var key = encodeURIComponent($('#input_apiKey')[0].value);

这里是HTML输入字段中的值经过URL编码转换成%20的地方。我计划在GitHub上的Swashbuckle存储库中开一个问题。

解决方法

在解决此问题之前,可以通过注入到Swagger UI中的JavaScript文件进行以下行替换的解决方法:

  1. 在安装了Swashbuckle的项目中,创建一个名为"Swagger"的新文件夹。

  2. 在新文件夹中创建一个名为"SwaggerUiCustomization.js"的JavaScript文件,并将以下脚本放入其中:

    (function () {
        function addApiKeyAuthorization() {
            var key = $('#input_apiKey')[0].value;
            if (key && key.trim() != "") {
                var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization(swashbuckleConfig.apiKeyName, key, swashbuckleConfig.apiKeyIn);
                window.swaggerUi.api.clientAuthorizations.add("api_key", apiKeyAuth);
                log("added key " + key);
            }
        }
        $('#input_apiKey').change(addApiKeyAuthorization);
    })();
    
  3. 在解决方案资源管理器中,选择文件并按Alt + Enter以编辑其属性。在属性窗口中将文件的生成操作更改为嵌入式资源

  4. 在你的SwaggerConfig.cs文件中,在EnableSwaggerUi()代码块内添加以下行: c.InjectJavaScript(thisAssembly, "<Project_Default_Namespace>.Swagger.SwaggerUiCustomization.js");
    当然,请确保将<Project_Default_Namespace>替换为你的项目默认命名空间。

  5. 运行你的项目并在文本框中输入"Bearer "。当你调用控制器操作时,你应该在服务器端得到这个完全相同的值 - 用一个空格代替%20%


我通过替换index.html文件解决了这个问题(实际上和你在JavaScript中所做的一样)。谢谢。 但是你有什么关于如何获取token的建议吗?因为“token”API不在Swagger文档中。当然,我可以通过Postman获取token,但这并不方便。 - Bagusflyer
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Bagusflyer
1
好的,谢谢 - 很棒的帖子和答案。终于让它工作了。救了我的命。 - richardb
@richardb Swashbuckle v5.5.0 刚刚在3小时前发布,其中已经内置了修复程序。 - urig
1
啊,这解释了一切,谢谢 - 昨天我一直没有成功,今天早上只是更新了软件包。现在一切都很好,像梦一样工作。 - richardb
显示剩余7条评论

16

在ASP.NET Framework Web API中,我成功地通过两种不同的方式在UI上添加了Bearer令牌,并使其正常工作。

方式1:

添加操作过滤器。创建以下类:

public class AuthorizationHeaderParameterOperationFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (operation.parameters == null)
        {
            operation.parameters = new List<Parameter>();
            
        }
        operation.parameters.Add(new Parameter
        {
            name = "Authorization",
            @in = "header",
            description = "access token",
            required = false,
            type = "string",
            @default = "Bearer "
        });
    }
}

现在在SwaggerConfig.cs中添加以下内容:

GlobalConfiguration.Configuration
            .EnableSwagger(c =>
                {
                     // other settings

                     c.OperationFilter<AuthorizationHeaderParameterOperationFilter>();
             })
            .EnableSwaggerUi(c =>
                {
                    // UI configurations
            });

第二种方式:

我们也可以使用DocumentFilter来遍历所有操作并添加标题,在下面的方法中,我们跳过了第一次获取用户名和密码以及生成令牌的操作:

public class SwaggerPathDescriptionFilter : IDocumentFilter
{
    private string tokenUrlRoute = "Auth";
    // the above is the action which returns token against valid credentials
    private Dictionary<HeaderType, Parameter> headerDictionary;
    private enum HeaderType { TokenAuth };

    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
    {
        CreateHeadersDict();

        var allOtherPaths = swaggerDoc.paths.Where(entry => !entry.Key.Contains(tokenUrlRoute)) //get the other paths which expose API resources and require token auth
            .Select(entry => entry.Value)
            .ToList();

        foreach (var path in allOtherPaths)
        {
            AddHeadersToPath(path, HeaderType.TokenAuth);
        }
    }

    /// <summary>
    /// Adds the desired header descriptions to the path's parameter list
    /// </summary>
    private void AddHeadersToPath(PathItem path, params HeaderType[] headerTypes)
    {
        if (path.parameters != null)
        {
            path.parameters.Clear();
        }
        else
        {
            path.parameters = new List<Parameter>();
        }

        foreach (var type in headerTypes)
        {
            path.parameters.Add(headerDictionary[type]);
        }

    }

    /// <summary>
    /// Creates a dictionary containin all header descriptions
    /// </summary>
    private void CreateHeadersDict()
    {
        headerDictionary = new Dictionary<HeaderType, Parameter>();


        headerDictionary.Add(HeaderType.TokenAuth, new Parameter() //token auth header
        {
            name = "Authorization",
            @in = "header",
            type = "string",
            description = "Token Auth.",
            required = true,
            @default = "Bearer "
        });
    }
}

然后我们需要在SwaggerConfig.cs中注册它:

GlobalConfiguration.Configuration
            .EnableSwagger(c =>
                {
                     // other settings

                     c.DocumentFilter<SwaggerPathDescriptionFilter>();
             })
            .EnableSwaggerUi(c =>
                {
                    // UI configurations
            });

现在我们将在Swagger UI的头部中看到令牌输入,如下所示:

enter image description here


2
谢谢,你帮我省了两天的搜索时间,第二种方法对我有用,非常感激。 - Abdessamad Jadid
1
@AbdessamadJadid,很高兴知道它对你有用! - Ehsan Sajjad
谢谢,第一种方法对我有效。 - M Daim Khan

12

注意:此示例使用 Json Web Tokens。

您的代码可以设置为在授权字符串中不需要“Bearer”。

WebApi 项目中检索令牌的代码(请参见下面代码段中的 token = ...):

private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
    {
        token = null;
        IEnumerable<string> authzHeaders;
        if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
        {
            return false;
        }
        var bearerToken = authzHeaders.ElementAt(0);
        token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
        return true;
    }

Swagger ApiKey:

c.ApiKey("Authorization")
                        .Description("Filling bearer token here")
                        .Name("Bearer")
                        .In("header");

启用Swagger的ApiKey支持:

c.EnableApiKeySupport("Authorization", "header");

将令牌粘贴到Swagger UI中的Api_Key表单元素中: enter image description here 在Swagger请求头中的显示方式: enter image description here

在计算机重新启动或浏览器刷新后,有没有一种方法可以存储令牌? - user12425844
通常令牌的寿命很短,只请求授权几个请求。您能否提供此需求的更多详细信息?有您担心的场景吗? - Jeremy Ray Brown
你可以使用浏览器的session storage:https://www.w3schools.com/html/html5_webstorage.asp - Jeremy Ray Brown
存储这个的命令行是什么?我正在尝试弄清楚@jeremyraybrown。 - user12425844
在您的SwaggerConfig.cs文件中,您调用EnableSwaggerUI方法。您传递了一个SwaggerUIConfig对象。该对象有一个InjectJavaScript方法。那就是您提供JavaScript给Swagger的地方。示例:c.InjectJavaScript(typeof(MySwaggerConfigClass)).Assembly, "Namespace.To.my-javascriptfile.js");。您的JavaScript应等待DOM准备好后将存储的令牌加载到其中。在输入上放置一个事件侦听器,每当其值发生更改时保存令牌。 - Jeremy Ray Brown
显示剩余2条评论

9

OpenAPI 3更新,Swashbuckle.AspNetCore (6.7.1)的完整文章地址: https://codeburst.io/api-security-in-swagger-f2afff82fb8e 向Swagger添加JWT Bearer授权的代码。将其添加到Startup.cs的ConfigureServices方法中:

services.AddSwaggerGen(c =>
{
    // configure SwaggerDoc and others

    // add JWT Authentication
    var securityScheme = new OpenApiSecurityScheme
    {
        Name = "JWT Authentication",
        Description = "Enter JWT Bearer token **_only_**",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.Http,
        Scheme = "bearer", // must be lower case
        BearerFormat = "JWT",
        Reference = new OpenApiReference
        {
            Id = JwtBearerDefaults.AuthenticationScheme,
            Type = ReferenceType.SecurityScheme
        }
    };
    c.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme);
    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {securityScheme, new string[] { }}
    });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接