简体   繁体   中英

Swagger Authorization bearer not send

I'm using Swagger Swashbuckle in a dotnet core 3.1 web api project and have trouble to send bearer authorization to the requests calls. I've defined this in my ConfigureServices method:

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo() { Title = "MyApi", Version = "v1" });
            // Set the comments path for the Swagger JSON and UI.
            var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
            var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
            c.IncludeXmlComments(xmlPath);
            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Type = SecuritySchemeType.OAuth2,
                Flows = new OpenApiOAuthFlows()
                {
                    Password = new OpenApiOAuthFlow()
                    {

                        TokenUrl = new Uri("/api/Account/Login", UriKind.Relative),
                    }
                },
                In = ParameterLocation.Header,
                Name = "Authorization",
                Scheme = "Bearer",
            });
            c.AddSecurityRequirement(new OpenApiSecurityRequirement()
            {
                {
                    new OpenApiSecurityScheme()
                    {
                        Reference = new OpenApiReference()
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                        },
                        Scheme = "Bearer",
                        Type = SecuritySchemeType.Http,
                        Name = "Bearer",
                        In = ParameterLocation.Header
                    }, new List<string>()
                }
            });
        });

When running, I see the Authorize button that show the login dialog: 登录对话框

Once logged, the API routes show the locked padlock but when I try to use them, I see the call is done without the returned bearer:

curl -X GET "http://localhost:5000/api/Account" -H "accept: */*" -H "Authorization: Bearer undefined"

What's wrong with my definitions?

In the cURL request you can see: -H "Authorization: Bearer undefined". This means that when Swagger-UI tries to get the token that will be added to the request header, it cannot be found.

Then, where the token cames from, and why Swagger-UI cannot found it? The token comes in the json returned from your login endpoint (/api/Account/Login).

You must be sure that returned json from your login endpoint repect the expected format for a OAuth password flow, as explained in the RFC6749 section 4.1.4 (Access Token Response).

From your login endpoint you must return a json response like this:

{
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"bearer"
}

It's a common mistake, that when you serialize the response from the controller you dont respect the json property names. In example: you can be returning a json like this:

{
       "accessToken":"2YotnFZFEjr1zCsicMWpAA",
       "tokenType":"bearer"
}

Where "accessToken" is not the same as "access_token" and so on.

This little difference causes that Swagger-UI cannot found the bearer token when it deserializes the returned json.

TIP: decorate the "AccessToken" property of your response object, so it will be serialized correctly.

[JsonPropertyName("access_token")]
[JsonProperty(PropertyName = "access_token")]
public string AccessToken { get; set; }

Although what is explained is the main point of your problem, I want to tell you that adding the security requirement globally is not the most correct way to do it. In this way you are protecting all the endpoints, regardless of whether they are decorated with the Authorize attribute or not.

In the startup you only must set a "Security Definition", and add an "OperationFilter" that handles the "security requirements". Then "SecurityRequirement" references the "SecurityDefinition", then you don't repeat the security definition configuration (Scheme, Type, Name, In, etc.) inside the security requirements as you are doing in your example.

Refer to this github post that shows you the correct way to do it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM