我正在使用Swagger与keycloak。我得到了下面的错误,当我点击执行按钮。
当我在swagger上点击Execute时,我看到了正在加载的图像,并且在网络抽头上没有任何请求,因为我在控制台上有一个错误。
我将添加我的配置代码和YML文件,让你看到我做什么。
谁能帮帮我,好吗?
以下是控制台中的输出:
以下是控制台点击中的错误代码(其生成的代码):
下面是swagger用户界面页面:
下面是swagger配置:
@Slf4j
@Configuration
@TbCoreComponent
public class SwaggerConfiguration {
@Value("${swagger.api_path_regex}")
private String apiPathRegex;
@Value("${swagger.security_path_regex}")
private String securityPathRegex;
@Value("${swagger.non_security_path_regex}")
private String nonSecurityPathRegex;
@Value("${swagger.title}")
private String title;
@Value("${swagger.description}")
private String description;
@Value("${swagger.contact.name}")
private String contactName;
@Value("${swagger.contact.url}")
private String contactUrl;
@Value("${swagger.contact.email}")
private String contactEmail;
@Value("${swagger.version}")
private String version;
@Value("${app.version:unknown}")
private String appVersion;
// Used to get token from Keyclaok
@Value("${swagger.auth.token_url}")
private String keycloakAuthTokenUrl;
@Value("${security.keycloak.realm}")
private String keycloakRealm;
@Value("${security.keycloak.clientId}")
private String keyclaokAuthCliendId;
@Bean
public Docket yousefApi() {
TypeResolver typeResolver = new TypeResolver();
return new Docket(DocumentationType.SWAGGER_2)
.groupName("Hammad")
.apiInfo(apiInfo())
.additionalModels(
typeResolver.resolve(ThingsboardErrorResponse.class),
typeResolver.resolve(ThingsboardCredentialsExpiredResponse.class)
)
.select()
.paths(apiPaths())
.paths(any())
.build()
.globalResponses(HttpMethod.GET, defaultErrorResponses(false))
.globalResponses(HttpMethod.POST, defaultErrorResponses(true))
.globalResponses(HttpMethod.DELETE, defaultErrorResponses(false))
.securitySchemes(newArrayList(apiKey()))
.securityContexts(newArrayList(securityContext()))
.enableUrlTemplating(true);
}
@Bean
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER)
ApiListingBuilderPlugin loginEndpointListingBuilder() {
return new ApiListingBuilderPlugin() {
@Override
public void apply(ApiListingContext apiListingContext) {
if (apiListingContext.getResourceGroup().getGroupName().equals("Hammad")) {
ApiListing apiListing = apiListingContext.apiListingBuilder().build();
if (apiListing.getResourcePath().equals(keycloakAuthTokenUrl)) {
apiListingContext.apiListingBuilder().tags(Set.of(new Tag("login-endpoint", "Login Endpoint")));
apiListingContext.apiListingBuilder().description("Login Endpoint");
}
}
}
@Override
public boolean supports(@NotNull DocumentationType delimiter) {
return DocumentationType.SWAGGER_2.equals(delimiter) || DocumentationType.OAS_30.equals(delimiter);
}
};
}
@Bean
UiConfiguration uiConfig() {
return UiConfigurationBuilder.builder()
.deepLinking(true)
.displayOperationId(false)
.defaultModelsExpandDepth(1)
.defaultModelExpandDepth(1)
.defaultModelRendering(ModelRendering.EXAMPLE)
.displayRequestDuration(false)
.docExpansion(DocExpansion.NONE)
.filter(false)
.maxDisplayedTags(null)
.operationsSorter(OperationsSorter.ALPHA)
.showExtensions(false)
.showCommonExtensions(false)
.supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS)
.validatorUrl(null)
.persistAuthorization(true)
.syntaxHighlightActivate(true)
.syntaxHighlightTheme("agate")
.build();
}
private ApiKey apiKey() {
return new ApiKey("Bearer", "X-Authorization", "header");
}
private OAuth securityScheme() {
List<GrantType> grantTypes = newArrayList(new ResourceOwnerPasswordCredentialsGrant(keycloakAuthTokenUrl));
return new OAuth("KeycloakAuth", new ArrayList<>(), grantTypes);
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.operationSelector(securityPathOperationSelector())
.build();
}
private Predicate<String> apiPaths() {
return regex(apiPathRegex);
}
private Predicate<OperationContext> securityPathOperationSelector() {
return new SecurityPathOperationSelector(securityPathRegex, nonSecurityPathRegex);
}
private AuthorizationScope[] scopes() {
AuthorizationScope[] authorizationScopes = new AuthorizationScope[3];
authorizationScopes[0] = new AuthorizationScope(Authority.SYS_ADMIN.name(), "System administrator");
authorizationScopes[1] = new AuthorizationScope(Authority.TENANT_ADMIN.name(), "Tenant administrator");
authorizationScopes[2] = new AuthorizationScope(Authority.CUSTOMER_USER.name(), "Customer");
return authorizationScopes;
}
List<SecurityReference> defaultAuth() {
return newArrayList(new SecurityReference("KeycloakAuth", scopes()), new SecurityReference("Bearer", scopes()));
}
private ApiInfo apiInfo() {
String apiVersion = version;
if (StringUtils.isEmpty(apiVersion)) {
apiVersion = appVersion;
}
return new ApiInfoBuilder()
.title(title)
.description(description)
.contact(new Contact(contactName, contactUrl, contactEmail))
.version(apiVersion)
.build();
}
/**Helper methods**/
private List<Response> defaultErrorResponses(boolean isPost) {
return List.of(
errorResponse("400", "Bad Request",
ThingsboardErrorResponse.of(isPost ? "Invalid request body" : "Invalid UUID string: 123", ThingsboardErrorCode.BAD_REQUEST_PARAMS, HttpStatus.BAD_REQUEST)),
errorResponse("401", "Unauthorized",
ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
errorResponse("403", "Forbidden",
ThingsboardErrorResponse.of("You don't have permission to perform this operation!",
ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN)),
errorResponse("404", "Not Found",
ThingsboardErrorResponse.of("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND, HttpStatus.NOT_FOUND)),
errorResponse("429", "Too Many Requests",
ThingsboardErrorResponse.of("Too many requests for current tenant!",
ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS))
);
}
private Response errorResponse(String code, String description, ThingsboardErrorResponse example) {
return errorResponse(code, description, List.of(errorExample("error-code-" + code, description, example)));
}
private Response errorResponse(String code, String description, List<Example> examples) {
return errorResponse(code, description, examples, ThingsboardErrorResponse.class);
}
private Response errorResponse(String code, String description, List<Example> examples,
Class<? extends ThingsboardErrorResponse> errorResponseClass) {
return new ResponseBuilder()
.code(code)
.description(description)
.examples(examples)
.representation(MediaType.APPLICATION_JSON)
.apply(classRepresentation(errorResponseClass, true))
.build();
}
private Example errorExample(String id, String summary, ThingsboardErrorResponse example) {
return new ExampleBuilder()
.mediaType(MediaType.APPLICATION_JSON_VALUE)
.summary(summary)
.id(id)
.value(example).build();
}
private Consumer<RepresentationBuilder> classRepresentation(Class<?> clazz, boolean isResponse) {
return r -> r.model(
m ->
m.referenceModel(ref ->
ref.key(k ->
k.qualifiedModelName(q ->
q.namespace(clazz.getPackageName())
.name(clazz.getSimpleName())).isResponse(isResponse)))
);
}
private static class SecurityPathOperationSelector implements Predicate<OperationContext> {
private final Predicate<String> securityPathSelector;
SecurityPathOperationSelector(String securityPathRegex, String nonSecurityPathRegex) {
this.securityPathSelector = (not(regex(nonSecurityPathRegex)));
}
@Override
public boolean test(OperationContext operationContext) {
return this.securityPathSelector.test(operationContext.requestMappingPattern());
}
}
}
以下是YML文件:
swagger:
auth:
token_url: ${security.keycloak.serverUrl}/realms/${security.keycloak.realm}/protocol/openid-connect/token/
auth_url: ${security.keycloak.serverUrl}/realms/${security.keycloak.realm}/protocol/openid-connect/auth/
api_path_regex: "${SWAGGER_API_PATH_REGEX:/api/(customer|device|user|tenant).*}"
security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api/(customer|device|user|tenant).*}"
non_security_path_regex: "${SWAGGER_NON_SECURITY_PATH_REGEX:/api/(?:noauth|v1)/.*}"
title: "${SWAGGER_TITLE:yousefCo REST API}"
description: "${SWAGGER_DESCRIPTION: yousefCo open-source IoT platform REST API documentation.}"
contact:
name: "${SWAGGER_CONTACT_NAME:yousefCo Team}"
url: "${SWAGGER_CONTACT_URL:http://iot.test.net}"
email: "${SWAGGER_CONTACT_EMAIL:info@gmail.com}"
license:
title: "${SWAGGER_LICENSE_TITLE:Apache License Version 2.0}"
url: "${SWAGGER_LICENSE_URL:https://github.com/yousef/yousef/blob/master/LICENSE}"
version: "${SWAGGER_VERSION:}"
1条答案
按热度按时间ryoqjall1#
我认为您混合了Swagger版本2和3之间的配置,您的整体设置配置为在Swagger 3.0中使用,因此
首先,您必须将
DocumentationType
更改为OAS_30
。第二,使用
ApiKey
安全方案时,请注意,在调用API时,字段名将用作头,因此必须将其更改为:请注意,您必须在标记前添加
Bearer
单词,还必须将名称SecurityReference
更改为X-Authorization
。第三,如果您需要配置
OAuth2
安全方案,请使用OAuth2Scheme
构建器类和password
流,而不是使用OAuth
类,如下所示:不要忘记将
SecurityReference
中的相同作用域添加到OAuth2Scheme
作用域中。