如何在Spring启动rest应用程序中使用Swagger ui使用密码流配置oAuth2

我有使用另一个Spring启动授权服务器的spring boot rest api(resources),我已经将Swagger配置添加到资源应用程序中,以便为其余的API获得一个漂亮而快速的文档/测试平台。 我的Swagger配置如下所示:

@Configuration @EnableSwagger2 public class SwaggerConfig { @Autowired private TypeResolver typeResolver; @Value("${app.client.id}") private String clientId; @Value("${app.client.secret}") private String clientSecret; @Value("${info.build.name}") private String infoBuildName; public static final String securitySchemaOAuth2 = "oauth2"; public static final String authorizationScopeGlobal = "global"; public static final String authorizationScopeGlobalDesc = "accessEverything"; @Bean public Docket api() { List list = new java.util.ArrayList(); list.add(new ResponseMessageBuilder() .code(500) .message("500 message") .responseModel(new ModelRef("JSONResult«string»")) .build()); list.add(new ResponseMessageBuilder() .code(401) .message("Unauthorized") .responseModel(new ModelRef("JSONResult«string»")) .build()); return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) .build() .securitySchemes(Collections.singletonList(securitySchema())) .securityContexts(Collections.singletonList(securityContext())) .pathMapping("/") .directModelSubstitute(LocalDate.class,String.class) .genericModelSubstitutes(ResponseEntity.class) .alternateTypeRules( newRule(typeResolver.resolve(DeferredResult.class, typeResolver.resolve(ResponseEntity.class, WildcardType.class)), typeResolver.resolve(WildcardType.class))) .useDefaultResponseMessages(false) .apiInfo(apiInfo()) .globalResponseMessage(RequestMethod.GET,list) .globalResponseMessage(RequestMethod.POST,list); } private OAuth securitySchema() { List authorizationScopeList = newArrayList(); authorizationScopeList.add(new AuthorizationScope("global", "access all")); List grantTypes = newArrayList(); final TokenRequestEndpoint tokenRequestEndpoint = new TokenRequestEndpoint("http://server:port/oauth/token", clientId, clientSecret); final TokenEndpoint tokenEndpoint = new TokenEndpoint("http://server:port/oauth/token", "access_token"); AuthorizationCodeGrant authorizationCodeGrant = new AuthorizationCodeGrant(tokenRequestEndpoint, tokenEndpoint); grantTypes.add(authorizationCodeGrant); OAuth oAuth = new OAuth("oauth", authorizationScopeList, grantTypes); return oAuth; } private SecurityContext securityContext() { return SecurityContext.builder().securityReferences(defaultAuth()) .forPaths(PathSelectors.ant("/api/**")).build(); } private List defaultAuth() { final AuthorizationScope authorizationScope = new AuthorizationScope(authorizationScopeGlobal, authorizationScopeGlobalDesc); final AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; return Collections .singletonList(new SecurityReference(securitySchemaOAuth2, authorizationScopes)); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title(“My rest API") .description(" description here … ”) .termsOfServiceUrl("https://www.example.com/") .contact(new Contact(“XXXX XXXX”, "http://www.example.com", “xxxx@example.com”)) .license("license here”) .licenseUrl("https://www.example.com") .version("1.0.0") .build(); } } 

我从授权服务器获取访问令牌的方法是使用http POST到此链接,并在clientid / clientpass的标头中使用基本授权:

 http://server:port/oauth/token?grant_type=password&username=&password= 

响应是这样的:

 { "access_token": "e3b98877-f225-45e2-add4-3c53eeb6e7a8", "token_type": "bearer", "refresh_token": "58f34753-7695-4a71-c08a-d40241ec3dfb", "expires_in": 4499, "scope": "read trust write" } 

在Swagger UI中我可以看到一个授权按钮,它打开一个对话框来发出授权请求,但是它没有工作,并指示我如下链接,

 http://server:port/oauth/token?response_type=code&redirect_uri=http%3A%2F%2Fserver%3A8080%2Fwebjars%2Fspringfox-swagger-ui%2Fo2c.html&realm=undefined&client_id=undefined&scope=global%2CvendorExtensions&state=oauth 

我在这里失踪了什么?

Swagger UI有一个授权按钮

8个月后,最后在Swagger UI中支持密码流,这是最终的代码和设置,对我有用:

1)Swagger配置:

 package com.example.api; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.bind.annotation.RequestMethod; import springfox.documentation.schema.ModelRef; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.AuthorizationScope; import springfox.documentation.service.Contact; import springfox.documentation.service.GrantType; import springfox.documentation.service.OAuth; import springfox.documentation.service.ResourceOwnerPasswordCredentialsGrant; import springfox.documentation.service.ResponseMessage; import springfox.documentation.service.SecurityReference; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.builders.ResponseMessageBuilder; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger.web.ApiKeyVehicle; import springfox.documentation.swagger.web.SecurityConfiguration; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.Collections; import java.util.List; import static com.google.common.collect.Lists.*; @Configuration @EnableSwagger2 public class SwaggerConfig { @Value("${app.client.id}") private String clientId; @Value("${app.client.secret}") private String clientSecret; @Value("${info.build.name}") private String infoBuildName; @Value("${host.full.dns.auth.link}") private String authLink; @Bean public Docket api() { List list = new java.util.ArrayList<>(); list.add(new ResponseMessageBuilder().code(500).message("500 message") .responseModel(new ModelRef("Result")).build()); list.add(new ResponseMessageBuilder().code(401).message("Unauthorized") .responseModel(new ModelRef("Result")).build()); list.add(new ResponseMessageBuilder().code(406).message("Not Acceptable") .responseModel(new ModelRef("Result")).build()); return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()).build().securitySchemes(Collections.singletonList(securitySchema())) .securityContexts(Collections.singletonList(securityContext())).pathMapping("/") .useDefaultResponseMessages(false).apiInfo(apiInfo()).globalResponseMessage(RequestMethod.GET, list) .globalResponseMessage(RequestMethod.POST, list); } private OAuth securitySchema() { List authorizationScopeList = newArrayList(); authorizationScopeList.add(new AuthorizationScope("read", "read all")); authorizationScopeList.add(new AuthorizationScope("trust", "trust all")); authorizationScopeList.add(new AuthorizationScope("write", "access all")); List grantTypes = newArrayList(); GrantType creGrant = new ResourceOwnerPasswordCredentialsGrant(authLink+"/oauth/token"); grantTypes.add(creGrant); return new OAuth("oauth2schema", authorizationScopeList, grantTypes); } private SecurityContext securityContext() { return SecurityContext.builder().securityReferences(defaultAuth()).forPaths(PathSelectors.ant("/user/**")) .build(); } private List defaultAuth() { final AuthorizationScope[] authorizationScopes = new AuthorizationScope[3]; authorizationScopes[0] = new AuthorizationScope("read", "read all"); authorizationScopes[1] = new AuthorizationScope("trust", "trust all"); authorizationScopes[2] = new AuthorizationScope("write", "write all"); return Collections.singletonList(new SecurityReference("oauth2schema", authorizationScopes)); } @Bean public SecurityConfiguration securityInfo() { return new SecurityConfiguration(clientId, clientSecret, "", "", "", ApiKeyVehicle.HEADER, "", " "); } private ApiInfo apiInfo() { return new ApiInfoBuilder().title("My API title").description("") .termsOfServiceUrl("https://www.example.com/api") .contact(new Contact("Hasson", "http://www.example.com", "hasson@example.com")) .license("Open Source").licenseUrl("https://www.example.com").version("1.0.0").build(); } } 

2)在POM中使用这个Swagger UI版本2.7.0:

   io.springfox springfox-swagger2 2.7.0   io.springfox springfox-swagger-ui 2.7.0   io.springfox springfox-bean-validators 2.7.0  

3)在application.properties中添加以下属性:

 host.full.dns.auth.link=http://oauthserver.example.com:8081 app.client.id=test-client app.client.secret=clientSecret auth.server.schem=http 

4)在Authorization服务器中添加一个CORSfilter:

 package com.example.api.oauth2.oauth2server; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * Allows cross origin for testing swagger docs using swagger-ui from local file * system */ @Component public class CrossOriginFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(CrossOriginFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { // Called by the web container to indicate to a filter that it is being // placed into service. // We do not want to do anything here. } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { log.info("Applying CORS filter"); HttpServletResponse response = (HttpServletResponse) resp; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "0"); chain.doFilter(req, resp); } @Override public void destroy() { // Called by the web container to indicate to a filter that it is being // taken out of service. // We do not want to do anything here. } } 

如果您使用这些设置运行,您将获得链接http://apiServer.example.com:8080/swagger-ui.html#/ (如果您在8080上运行)中的授权按钮,如下所示:

在此处输入图像描述

然后,当您单击授权按钮时,您将获得以下对话框,添加您的用户名/密码的数据以及客户端ID和客户端密钥,类型必须是请求正文,我不知道为什么但这是有效的和我一起,虽然我认为它应该是基本的身份validation,因为这是客户端密码的发送方式,但无论如何,这就是Swagger-ui如何使用密码流并且所有API端点都在重新运行。 快乐大摇大摆!!! 🙂

在此处输入图像描述

我不确定你的问题是什么,但授权按钮对我来说是swagger版本2.7.0,虽然我必须手动获取JWT令牌。

首先我为auth令牌命中,然后我插入如下的令牌,

在此处输入图像描述

这里的关键是我的令牌是JWT,我无法在Bearer **之后插入令牌值并将** api_key名称更改Authorization并且我使用以下Java配置实现了

 @Bean public SecurityConfiguration securityInfo() { return new SecurityConfiguration(null, null, null, null, "", ApiKeyVehicle.HEADER,"Authorization",": Bearer"); } 

关于范围分隔符 ,似乎有一个错误,默认情况下是 。 在我的配置中,我试图将其修改为: Bearer但是没有发生,所以我必须在UI上输入它。

到目前为止使用oAuth2授权的最好方法是使用Swagger编辑器,我在Docker中快速安装了Swagger Editor(从这里开始 ),然后使用import参数下载API JSON描述符(你的API应包括CORSfilter),然后我可以获得Swagger文档和一个界面,我可以使用curl,postman或Firefox rest客户端添加令牌。

我现在使用的链接看起来像这样

http://docker.example.com/#/?import=http://mywebserviceapi.example.com:8082/v2/api-docs&no-proxy

Swagger编辑器中输入令牌的界面如下所示:

在此处输入图像描述

如果有更好的解决方案或解决方法,请在此处发布您的答案。

这是swagger-ui 2.6.1上的一个错误,每次都会发送vendorExtensions范围。 这导致请求超出范围,导致拒绝请求。 由于招摇无法获得访问令牌,因此无法通过oauth2

在maven上升级应该可以解决问题。 最低版本应为2.7.0