JWT Authentication and Swagger with .Net core 3.0

2020-03-17 05:13发布

问题:

I am developing some Web Api with .Net core 3.0 and want to integrate it with SwashBuckle.Swagger. It is working fine, but when I add JWT authentication, it does not work as I expect. To do that, I added the code below:

  services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "My Web API", Version = "v1" });
            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey
            });

        });

After adding AddSecurityDefinition function, I can see the Authorize button and when I click it, I see the form below:

Then I type Bearer WhatEverApiKeyIsfgdgdgdg845734987fgdhgiher635kjh, After doing it I expect to see authorization: Bearer WhatEverApiKeyIsfgdgdgdg845734987fgdhgiher635kjh in the request's header , when I send a request to the Web Api from Swagger. But authorization is not added to the request header. I am using SwashBuckle.Swagger(5.0.0-rc3). Please note there are many samples which work fine on .net core 2.0, but Swashbuckle swagger functions has changed on the latest version so I cannot use that samples.

回答1:

After some research, I eventually found the answer here

Before seeing this page, I knew that I should use AddSecurityRequirement after AddSecurityDefinition because of many samples, but it was a problem that the function parameters have changed on .NET Core 3.0.

By the way, the final answer is as below:

services.AddSwaggerGen(c =>
{
  c.SwaggerDoc("v1", new OpenApiInfo { 
    Title = "My API", 
    Version = "v1" 
  });
  c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
    In = ParameterLocation.Header, 
    Description = "Please insert JWT with Bearer into field",
    Name = "Authorization",
    Type = SecuritySchemeType.ApiKey 
  });
  c.AddSecurityRequirement(new OpenApiSecurityRequirement {
   { 
     new OpenApiSecurityScheme 
     { 
       Reference = new OpenApiReference 
       { 
         Type = ReferenceType.SecurityScheme,
         Id = "Bearer" 
       } 
      },
      new string[] { } 
    } 
  });
});


回答2:

If you are using Swagger 3.0 then it has build-in support for JWT authentication.

You need to use ParameterLocation.Header, SecuritySchemeType.Http, bearer, and JWT in OpenApiSecurityScheme as shown below.

After this, you wouldn't need to specify token in Bearer {token} format. Only specify the token and the security scheme will automatically apply it in the header.

// Bearer token authentication
OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme()
{
    Name = "Bearer",
    BearerFormat = "JWT",
    Scheme = "bearer",
    Description = "Specify the authorization token.",
    In = ParameterLocation.Header,
    Type = SecuritySchemeType.Http,
};
c.AddSecurityDefinition("jwt_auth", securityDefinition);

// Make sure swagger UI requires a Bearer token specified
OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme()
{
    Reference = new OpenApiReference()
    {
        Id = "jwt_auth",
        Type = ReferenceType.SecurityScheme
    }
};
OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement()
{
    {securityScheme, new string[] { }},
};
c.AddSecurityRequirement(securityRequirements);



回答3:

If you don't want to add a token manually and you want the scopes to be selectable along with passing a clientId to the identity server you can add something like this.

I have used implicit flow, but you can configure any flow using the following mechanism:

options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme()
{
  Flows = new OpenApiOAuthFlows
  {
    Implicit = new OpenApiOAuthFlow
    {                            
      AuthorizationUrl = new Uri("http://localhost"),
      TokenUrl = new Uri("http://localhost"),
      Scopes = new Dictionary<string, string>
      {
        { "Foundation API", "FoundationApi" }
      }
    }
  },
  In = ParameterLocation.Header,                    
  Name = "Authorization",
  Type = SecuritySchemeType.OAuth2                    
});

The output will be like this: