1 package cn.home1.oss.lib.swagger.starter;
2
3 import static cn.home1.oss.lib.swagger.SwaggerUtils.apiInfo;
4 import static com.google.common.base.Predicates.not;
5 import static com.google.common.base.Predicates.or;
6 import static com.google.common.collect.Lists.newArrayList;
7 import static com.google.common.collect.Sets.newLinkedHashSet;
8 import static java.util.stream.Collectors.toList;
9 import static org.apache.commons.lang3.StringUtils.isNotBlank;
10 import static springfox.documentation.builders.PathSelectors.ant;
11 import static springfox.documentation.builders.PathSelectors.regex;
12
13 import com.google.common.base.Predicate;
14
15 import cn.home1.oss.boot.autoconfigure.AppUtils;
16 import cn.home1.oss.boot.autoconfigure.ConditionalOnNotEnvProduction;
17
18 import com.fasterxml.classmate.ResolvedType;
19
20 import lombok.extern.slf4j.Slf4j;
21
22 import org.springframework.beans.factory.annotation.Autowired;
23 import org.springframework.beans.factory.annotation.Qualifier;
24 import org.springframework.boot.autoconfigure.AutoConfigureAfter;
25 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
26 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
27 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
28 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
29 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
30 import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
31 import org.springframework.boot.autoconfigure.security.SecurityProperties;
32 import org.springframework.boot.autoconfigure.web.ServerProperties;
33 import org.springframework.context.annotation.Bean;
34 import org.springframework.context.annotation.ComponentScan;
35 import org.springframework.context.annotation.Configuration;
36 import org.springframework.context.annotation.Import;
37 import org.springframework.core.annotation.Order;
38 import org.springframework.core.env.Environment;
39 import org.springframework.security.config.annotation.ObjectPostProcessor;
40 import org.springframework.security.config.annotation.web.builders.WebSecurity;
41 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
42 import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
43 import org.springframework.security.web.util.matcher.OrRequestMatcher;
44 import org.springframework.security.web.util.matcher.RequestMatcher;
45
46 import springfox.documentation.RequestHandler;
47 import springfox.documentation.builders.RequestHandlerSelectors;
48 import springfox.documentation.spi.DocumentationType;
49 import springfox.documentation.spring.web.SpringfoxWebMvcConfiguration;
50 import springfox.documentation.spring.web.json.JacksonModuleRegistrar;
51 import springfox.documentation.spring.web.plugins.Docket;
52 import springfox.documentation.swagger.configuration.SwaggerCommonConfiguration;
53 import springfox.documentation.swagger2.configuration.Swagger2JacksonModule;
54
55 import java.util.List;
56 import java.util.Optional;
57 import java.util.Set;
58
59
60
61
62 @AutoConfigureAfter(SecurityAutoConfiguration.class)
63 @ConditionalOnNotEnvProduction
64 @ConditionalOnWebApplication
65 @Configuration
66 @Import({
67 SpringfoxWebMvcConfiguration.class,
68 SwaggerCommonConfiguration.class,
69 ManagementConfiguration.class,
70 NoManagementConfiguration.class})
71 @ComponentScan(basePackages = {
72 "springfox.documentation.swagger2.readers.parameter",
73 "springfox.documentation.swagger2.web",
74 "springfox.documentation.swagger2.mappers"})
75 @Slf4j
76 public class Swagger2DocumentationAutoConfiguration {
77
78 public static final String DOCKET_APPLICATION = "docketApplication";
79
80 @Autowired(required = false)
81 private ServerProperties serverProperties;
82
83 @Qualifier(NoManagementConfiguration.MANAGEMENT_PATHS)
84 @Autowired
85 public Predicate<String> managementPaths;
86
87 @Bean
88 public JacksonModuleRegistrar swagger2Module() {
89 return new Swagger2JacksonModule();
90 }
91
92 @ConditionalOnMissingBean(name = DOCKET_APPLICATION)
93 @Bean(name = DOCKET_APPLICATION)
94 public Docket docketApplication() {
95 final Docket docket = new Docket(DocumentationType.SWAGGER_2)
96 .apiInfo(apiInfo("application", "application's endpoints"))
97 .groupName("api")
98 .select()
99 .apis(or(this.applicationAips(), this.springApis()))
100 .paths(not(this.managementPaths))
101 .build();
102 final Optional<ResolvedType> modelResolvedError = ManagementConfiguration.modelResolvedError();
103 return modelResolvedError.isPresent() ? docket.additionalModels(modelResolvedError.get()) : docket;
104 }
105
106 private Predicate<String> errorPath() {
107 return ant(this.serverProperties.getError().getPath());
108 }
109
110 private Predicate<String> anyPath() {
111 return regex("/.*");
112 }
113
114 private Predicate<RequestHandler> applicationAips() {
115 final Predicate<RequestHandler> ossLibApi = RequestHandlerSelectors.basePackage("cn.home1");
116 final String applicationPackage = AppUtils.appBasePackage("");
117 return isNotBlank(applicationPackage) ?
118 or(RequestHandlerSelectors.basePackage(applicationPackage), ossLibApi) :
119 RequestHandlerSelectors.any();
120 }
121
122 private Predicate<RequestHandler> springApis() {
123 return RequestHandlerSelectors.basePackage("org.springframework");
124 }
125
126 @Configuration
127 @ConditionalOnClass(WebSecurityConfigurerAdapter.class)
128 @ConditionalOnBean(ObjectPostProcessor.class)
129 @ConditionalOnProperty(prefix = "security.basic", name = "enabled", matchIfMissing = true)
130 static class SwaggerSecurityConfiguration {
131
132 @Bean
133 public WebSecurityConfigurerAdapter swaggerSecurityConfigurer() {
134 return new Swagger2DocumentationAutoConfiguration.SwaggerSecurityConfiguration.SwaggerSecurityConfigurer();
135 }
136
137 @Order(SecurityProperties.BASIC_AUTH_ORDER - 11)
138 private static class SwaggerSecurityConfigurer extends WebSecurityConfigurerAdapter {
139
140 @Autowired
141 private Environment environment;
142
143 @Override
144 public void init(final WebSecurity web) throws Exception {
145 final RequestMatcher requestMatcher = swaggerRequestMatcher();
146 if (requestMatcher != null) {
147 web.ignoring().requestMatchers(requestMatcher);
148 }
149
150 }
151
152
153
154
155
156
157
158
159
160 private RequestMatcher swaggerRequestMatcher() {
161 final Set<String> paths = newLinkedHashSet();
162
163 paths.add("/webjars/**");
164 paths.add(this.environment.getProperty("springfox.documentation.swagger.v1.path", "/v1/**"));
165 paths.add(this.environment.getProperty("springfox.documentation.swagger.v2.path", "/v2/**"));
166 paths.addAll(newArrayList("/swagger-ui.html", "/swagger-resources/**"));
167
168 final RequestMatcher requestMatcher;
169 if (!paths.isEmpty()) {
170 final List<RequestMatcher> matchers = paths.stream()
171 .map(pattern -> new AntPathRequestMatcher(pattern, null))
172 .collect(toList());
173 requestMatcher = new OrRequestMatcher(matchers);
174 } else {
175 requestMatcher = null;
176 }
177 return requestMatcher;
178 }
179 }
180 }
181 }