是否可以添加身份验证以访问 NestJS 的 Swagger Explorer

Is it possible to add Authentication to access to NestJS' Swagger Explorer

我目前在我的 NestJS 项目中使用 Swagger,并且启用了资源管理器:

main.js

const options = new DocumentBuilder()
    .setTitle('My App')
    .setSchemes('https')
    .setDescription('My App API documentation')
    .setVersion('1.0')
    .build()

const document = SwaggerModule.createDocument(app, options)
SwaggerModule.setup('docs', app, document, {
    customSiteTitle: 'My App documentation',
})

有了这个,资源管理器可以在 /docs 中访问,这正是我所期望的。但我想知道是否可以向资源管理器添加任何身份验证层,因此只接受某些请求。

我想让这个资源管理器在生产环境中可以访问,但仅限经过身份验证的用户。

提前致谢:)

对于遇到类似挑战的任何人,您可以在 Nestjs 中向您的 Swagger UI 添加身份验证,如下所示。

const options = new DocumentBuilder()
.setTitle('Sample Project API')
.setDescription('This is a sample project to demonstrate auth in Swagger UI')
.setVersion('1.0')
.addTag('Nestjs Swagger UI')
.setContactEmail('your_contact@mail.com')
.addBearerAuth('Authorization', 'header', 'basic')
.setBasePath('api')
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('docs', app, document);

所以 .addBearerAuth 需要 3 个参数(密钥名称、位置、身份验证类型)。授权类型可以是 basicbearerapikey

更新

根据最近对 DocumentBuilder 方法的更改,这对我来说是有效的。分享给正在使用新版本的人。

const options = new DocumentBuilder()
.setTitle('My API')
.setDescription('API used for testing purpose')
.setVersion('1.0.0')
.setBasePath('api')
.addBearerAuth(
  { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
  'access-token',
)
.build();

const document = SwaggerModule.createDocument(app, options);

更新另外,请在您的控制器功能上使用@ApiBearerAuth()添加授权。

@Get('/test')
@ApiBearerAuth()

access-token 是 swagger 文档中供参考的名称。您在 header 中的令牌将按如下方式传递:

curl -X GET "http://localhost:3004/test" -H "accept: application/json" -H "Authorization: Bearer test-token"

只需将 .addBearerAuth()(不带任何参数)添加到您的 swagger 选项中

@ApiBearerAuth()到您的控制器方法

const options = new DocumentBuilder()
    .setTitle('My App')
    .setSchemes('https')
    .setDescription('My App API documentation')
    .setVersion('1.0')
    .addBearerAuth()
    .build()

以下示例运行良好

.addBearerAuth({ in: 'header', type: 'http' })

你应该告诉 in prop

中令牌的位置在哪里

并且由于您覆盖了默认选项,因此您应该传递 type

  const options = new DocumentBuilder()
    .setTitle('Api docs for mobile')
    .setDescription('The api docs for the mobile application')
    .setVersion('1.0')
    .addBearerAuth({ in: 'header', type: 'http' })
    .build();

addBearerAuth 实施

    addBearerAuth(options = {
        type: 'http'
    }, name = 'bearer') {
        this.addSecurity(name, Object.assign({ scheme: 'bearer', bearerFormat: 'JWT' }, options));
        return this;
    }

这是 APIKEY 不持有者

万一有人到达此 post 并寻找 apiKey(而不是承载),您需要遵循此

在main.ts

    const options = new DocumentBuilder()
        .setTitle('CMOR')
        .setDescription('CMOR API documentation')
        .setVersion('1.0')
        .addServer('/api')
        .addApiKey({
            type: 'apiKey', // this should be apiKey
            name: 'api-key', // this is the name of the key you expect in header
            in: 'header',
        }, 'access-key' // this is the name to show and used in swagger
        ) 
        .build();

然后在你的控制器或方法中

@ApiTags('analyzer')
@ApiSecurity('access-key') // this is the name you set in Document builder
@Controller('analyzer')
export class ScreenAnalyzerController {

根据@nestjs/swagger 4.0 版中的 breaking/API 更改进行了更新。

嗨, 花了很多尝试和失败才能做到这一点。 代码中的注释是理解的重要内容。这些名称相互依赖才能发挥作用。

main.ts

    const options = new DocumentBuilder()
        .setTitle('my-title')
        .setDescription('my-descirption')
        .setVersion('1.0')
        .addBearerAuth(
          {
            type: 'http',
            scheme: 'bearer',
            bearerFormat: 'JWT',
            name: 'JWT',
            description: 'Enter JWT token',
            in: 'header',
          },
          'JWT-auth', // This name here is important for matching up with @ApiBearerAuth() in your controller!
        )
        .build();
      const document = SwaggerModule.createDocument(app, options);
      SwaggerModule.setup('api', app, document);

然后在您的控制器中执行以下操作(注意@ApiBearerAuth() 使用与 main.ts 中 swagger 选项中的名称相同的名称):

app.controller.ts

    @Roles(Role.Admin)
      @UseGuards(JwtAuthGuard, RolesGuard)
      @ApiTags('Admin')
      @ApiOperation({ summary: 'Get admin section' })
      @Get('admin')
      @ApiBearerAuth('JWT-auth') // This is the one that needs to match the name in main.ts
      getAdminArea(@Request() req) {
        return req.user;
      }

希望这可以节省一些人我理解发生了什么的时间。

使用 NestJS 和 Express 通过 HTTP 基本身份验证保护对 Swagger 的访问

首先 运行 npm i express-basic-auth 然后将以下内容添加到您的 main.{ts,js}:

// add import
import * as basicAuth from 'express-basic-auth';

// ...

// Sometime after NestFactory add this to add HTTP Basic Auth
app.use(
    ['/docs', '/docs-json'],
    basicAuth({
        challenge: true,
        users: {
            yourUserName: 'p4ssw0rd',
        },
    }),
);


// Your code
const options = new DocumentBuilder()
    .setTitle('My App')
    .setSchemes('https')
    .setDescription('My App API documentation')
    .setVersion('1.0')
    .build()

const document = SwaggerModule.createDocument(app, options)
SwaggerModule.setup('docs', app, document, {
    customSiteTitle: 'My App documentation',
})

// ...

有了这个,您将在任何 /docs 路由上收到带有 HTTP 基本身份验证提示的提示。我们也必须明确命名 /docs-json,以保护生成的 JSON OpenAPI 文件。

您不应将凭据放在 code/repository 中,而应放在 .env 中并通过 ConfigService.

访问

我第一次看到这个解决方案here

您可以通过添加 addApiKeyaddBearerAuth 示例来完成此问题的其他答案。

在我这边,我可以添加 OAuth2 身份验证 @nestjs/swagger3** 和@nestjs/swagger4**

在实现上有一些区别

For the @nestjs/swagger3**

const options = new DocumentBuilder()
    .setTitle('API')
    .setDescription('API')
    .setVersion('1.0')
    .setSchemes('https', 'http')
    .addOAuth2('implicit', AUTH_URL, TOKEN_URL)
    .build();

const document = SwaggerModule.createDocument(app, options);

SwaggerModule.setup(swaggerPath, app, document, {
    swaggerOptions: {
        oauth2RedirectUrl: REDIRECT_URL, // after successfully logging
        oauth: {
            clientId: CLIENT_ID,
        },
    },
});

addOAuth2 还支持密码、应用程序和访问代码等流程

For the @nestjs/swagger4**

const options = new DocumentBuilder()
    .setTitle('API')
    .setDescription('API description')
    .setVersion(version)
    .addServer(host)
    .addOAuth2(
        {
            type: 'oauth2',
            flows: {
                implicit: {
                    authorizationUrl: AUTH_URL + `?nonce=${getRandomNumber(9)}`, // nonce parameter is required and can be random, for example nonce=123456789
                    tokenUrl: TOKEN_URL,
                    scopes: SCOPES, // { profile: 'profile' }
                },
            },
        },
        'Authentication'
    )
    .build();

const document = SwaggerModule.createDocument(app, options);

SwaggerModule.setup(swaggerPath, app, document, {
    swaggerOptions: {
        oauth2RedirectUrl: REDIRECT_URL, // after successfully logging
        oauth: {
            clientId: CLIENT_ID,
        },
    },
});

对于无法通过上述答案解决的任何人。

这是我添加不记名令牌的方法

const options = new DocumentBuilder()
.setTitle('My API')
.setDescription('My api')
.setVersion('1.0.0')
.addBearerAuth(
  {
    type: 'http',
    scheme: 'bearer',
    bearerFormat: 'JWT',
    name: 'JWT',
    description: 'Enter JWT token',
    in: 'header',
  },
  'token'
)
.build();

添加后不要忘记添加装饰器@ApiBearerAuth('token')

还有一件事要注意,.addBearerAuth({...}, 'token') 方法中的第二个参数需要添加到装饰器中,这样只有您才能在 curl 请求中看到授权。

@Controller('api')
@ApiBearerAuth('token')

你也可以将它留空 @ApiBearerAuth() 并从

中删除第二个参数
.addBearerAuth(
{
    type: 'http',
    scheme: 'bearer',
    bearerFormat: 'JWT',
    name: 'JWT',
    description: 'Enter JWT token',
    in: 'header',
})

NestJS 文档需要改进

根据之前的答案,您可能会看到此错误(如果您想使用 express-basic-auth 模块

Type 'typeof expressBasicAuth' has no call signatures.

Type originates at this import. A namespace-style import cannot be called or constructed, and will cause a failure at runtime. Consider using a default import or import require here instead

对于这种情况,您可以在 main.ts

中使用 .default
import * as basicAuth from 'express-basic-auth';

async function bootstrap() {

  app.use(['/docs'], basicAuth.default({
    challenge: true,
    users: {
      [process.env.SWAGGER_USERNAME]: process.env.SWAGGER_PASSWORD,
    },
  }));

  const options = new DocumentBuilder()
      .setTitle('api')
      .setDescription('API description')
      .setVersion('1.0')
      .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('docs', app, document);

}

在你的 main.ts 文件中添加这个

 const config = new DocumentBuilder()
    .setTitle('App title')
    .setDescription("Api description")
    .setVersion('1.0')
    .addTag('ApiTag')
    .setContact('name', 'ulr', "email")
    .addBearerAuth({ type: 'http', schema: 'Bearer', bearerFormat: 'Token' } as SecuritySchemeObject, 'Bearer')
    .build();

控制器文件

@ApiBearerAuth("Bearer")
@Controller('posts')
export class PostController {
  constructor(private readonly postService: PostService) { }
}

Set your token