如何在 Express/JavaScript 中的 swagger 文档中实现 JWT 授权 header

How to implement JWT authorization header in swagger docs in Express/JavaScript

我正在尝试将以下配置添加到我的 swagger.config.ts:

const swaggerUiOptions = {
  explorer: true,
  swaggerOptions: {
    authAction: {
      JWT: {
        name: 'JWT',
        schema: {
          type: 'apiKey',
          in: 'header',
          name: 'Authorization',
          description: ''
        },
        value: 'Bearer <JWT token here>'
      }
    }
  }
};

那么在这下面,我有:

app.use('/api-docs', swaggerUi.serve, swaggerUI.setup(swaggerSpec, swaggerUiOptions));

但是,UI 中并没有出现我期望看到的授权按钮。我不确定整个配置文件中是否有某些东西可能会破坏我添加的内容,因为我没有写完整的东西,这里是:

import express from 'express';
import { Model } from "mongoose";
import swaggerJsdoc from "swagger-jsdoc";
import swaggerUi from "swagger-ui-express";
import m2s from 'mongoose-to-swagger';
import { readFileSync } from 'fs';

class SwaggerEndPointInformationDto {
readonly httpMethod: string
readonly httpPath: string

constructor(httpMethod: string, httpPath: string) {
this.httpMethod = httpMethod;
this.httpPath = httpPath
}
}

class SwaggerConfig {
// private readonly app: express.Application;
private built = false;
private static instance: SwaggerConfig;
private models = Array<Model<any>>();

public static getInstance() {
if (!this.instance) {
this.instance = new SwaggerConfig();
}
return this.instance;
}

registerModel(model: Model<any>) {
this.checkIsNotBuilt();
this.models.push(model);
}

// addPathAndMethod()

registerSwaggerPage(app: express.Application, listeners: [(entry: SwaggerEndPointInformationDto) => void]) {
// registerSwaggerPage(app: express.Application) {
this.built = true;

const packageJson = JSON.parse(readFileSync('./package.json').toString());
const swaggerOptions = {
definition: {
openapi: '3.0.0',
info: {
title: packageJson.name,
version: packageJson.version,
}
},
apis: [
'./dist/**/*.js',
],
};
// const swaggerSpec: {paths: never;} = swaggerJsdoc(swaggerOptions);
// @ts-ignore
const swaggerSpec: { paths: string; } = swaggerJsdoc(swaggerOptions);

const swaggerUiOptions = {
explorer: true,
swaggerOptions: {
authActions: {
JWT: {
name: 'JWT',
schema: {
type: 'apiKey',
in: 'header',
name: 'Authorization',
description: ''
},
value: 'Bearer <JWT Token here>'
}
}
}
};

// add to components.schemas
this.models.forEach(model => {
const swaggerModel = m2s(model)
// @ts-ignore
swaggerSpec.components.schemas.push(swaggerModel);
});

// add routes
app._router.stack.filter((e: { route: never; }) => e.route).forEach((element: any) => {
console.log(element)
// if (element?.route?.path?.startsWith('/')) {
//   const httpPath: string = element.route.path
//   // @ts-ignore
//   if (!swaggerSpec.paths[httpPath]) {
//     // @ts-ignore
//     swaggerSpec.paths[httpPath] = {}
//   }
//   // @ts-ignore
//   const pathInfo = swaggerSpec.paths[httpPath];
//   for (const e in Object.keys(element.route.methods)) {
//     const httpMethod = Object.keys(element.route.methods)[e]
//     // console.log(element.route.methods[httpMethod])
//     if (element.route.methods[httpMethod]) {
//       if(!pathInfo[httpMethod]) {
//         // @ts-ignore
//         pathInfo[httpMethod] = {
//           description: "This is a description",
//           content: {
//             // "application/json": {
//             //     "schema":
//             // }
//           }
//         }
//       }

//       // const eventDto = new SwaggerEndPointInformationDto(httpMethod, httpPath)
//       // listeners.forEach((fn: (entry: SwaggerEndPointInformationDto) => void) => fn(eventDto))
//     }
//   }
// }
});

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, swaggerUiOptions));
console.log(JSON.stringify(swaggerSpec, null, 2))

//app._router.stack.filter(e => e.route)
}

private checkIsNotBuilt() {
if (this.built) {
throw new Error('Swagger Configuration is already built.')
}
}

public static swaggerMethod2 = (description: string) => (target: Object, propertyKey: string) => {
// Object.defineProperty(target, propertyKey, { description });
console.log(description);
console.log(Object);
console.log(propertyKey);
};
}


// const swaggerMethod = (description: string) => (target: Object, propertyKey: string) => {
// console.log(description);
// console.log(Object);
// console.log(propertyKey);
// };
/*
const swaggerMethod22 = (description: string) => (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
// console.log(key);
// Object.defineProperty(target, propertyKey, { description });
console.log("*********************************");
console.log(description);
console.log(Object);
console.log(propertyKey);
return descriptor;
};
*/
function swaggerMethod(description: string) {
return function (
target: Object,
key: string | symbol,
descriptor: PropertyDescriptor
) {
return descriptor;
};
}

export { SwaggerConfig, swaggerMethod, SwaggerEndPointInformationDto };

当我尝试重构为:

const swaggerSpec = {
  swaggerDefinition: {}
}

我收到来自 TypeScript 的以下投诉:

A class member cannot have the 'const' keyword

此外,申请时:

* security
*   - Authorization: []

这个 yaml 文件的位置:

/**
* @openapi
* /api/v2/patients:
*   post:
*     tags: [Patients]
*     description: to create a new patient.
*     requestBody:
*       required: true
*       content:
*         application/json:
*           schema:
*             type: object
*             $ref: '#/components/schemas/NewPatientDto'
*     responses:
*       201:
*         description: Creates a new patient.
*         content:
*           application/json:
*             schema:
*             $ref: '#/components/schemas/NewUserDto'
*       415:
*         description: Only 'application/json'. incoming content is supported..
*         content:
*           application/json:
*             schema:
*             $ref: '#/components/schemas/BaseError415Dto'
*       500:
*         description: A server error. The returned object contains the exact nature of the error.
*         content:
*           application/json:
*             schema:
*             $ref: '#/components/schemas/BaseError500Dto'
*/
this.app.post(p().api.v2.patients.$url, [
authMiddleware.verifyJWT,
patientsMiddleware.createPatientContext,
patientsMiddleware.validateAndBuildNewPatientDto,
patientsMiddleware.validateSamePatientDoesNotExist,
patientsController.createPatient
])

我不确定你的实现,但根据 openapi 和我的实现,这对我有用,

你可以在securitySchemes的definition > components中添加授权,

const swaggerSpec = {
    definition: {
        openapi: '3.0.3',
        info: {
            title: packageJson.name,
            version: packageJson.version
        },
        components: {
            securitySchemes: {
                Authorization: {
                    type: "http",
                    scheme: "bearer",
                    bearerFormat: "JWT",
                    value: "Bearer <JWT token here>"
                }
            }
        }
    },
    apis: [
        './dist/**/*.js'
    ]
};

根据您的实施用途,

const swaggerUiOptions = {
  explorer: true
};

app.use('/api-docs', swaggerUi.serve, swaggerUI.setup(swaggerSpec, swaggerUiOptions));

还有一件事,特别是 api 的注释通行证,带授权的安全密钥,

/**
* @openapi
* /api/v2/patients:
*   post:
*     security:
*       - Authorization: []
*     tags: [Patients]
*     description: to create a new patient.
....

看起来:

每个 api 有锁图标:

点击后:

Try to update openapi version at least 3.0.3!