如何在 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!
我正在尝试将以下配置添加到我的 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!