背景
spring-boot版本2.6.13
swagger版本2.9.2
拦截器本来好好的,项目中添加了swagger后拦截器失效了。
解决
A
更改 spring 以使用 antmatchers 并在 application.properties 中配置它
spring.mvc.pathmatch.matching-strategy = ANT_PATH_MATCHER
B
在 spring 中启用 mvcmatchers 创建一个配置文件供 swagger 使用
在您想要的任何地方创建一个用于 swagger 配置的文件
添加这些注释
@EnableWebMvc
@EnableSwagger2
@Component
public class SwaggersConfigs {
}
C
在所有 Spring 应用程序中启用 mvcmatchers,将 @EnableWebMvc 注释放在 Spring Boot 应用程序的主类之上,如下所示
@EnableWebMvc
@EnableSwagger2
@SpringBootApplication
public class SwaggerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SwaggerDemoApplication.class, args);
}
}
我是在启动类和Swagger的配置类上都加上了**@EnableWebMvc
@EnableSwagger2**,然后问题解决了。
完整示例
依赖
<spring-boot.version>2.6.13</spring-boot.version>
<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
Swagger配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
@Configuration
@EnableSwagger2
@EnableWebMvc
public class SwaggerConfig {
@Bean
public Docket docket(Environment environment) {
boolean flag = environment.acceptsProfiles(Profiles.of("dev", "test"));
System.out.println("flag:" + flag);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("cdp_operate")
.select()
.apis(RequestHandlerSelectors.basePackage("com.xxx.web"))
.build()
.enable(flag); // 是否开启Swagger
}
private ApiInfo apiInfo() {
Contact contact = new Contact("LHH", "http://xxx.xxx.com/联系人访问链接", "lvhouhou@163.com");
return new ApiInfo(
"Demo Swagger", // 标题
"Swagger API", // 描述
"v1.0", // 版本
"http://terms.service.url/组织链接", // 组织链接
contact, // 联系人信息
"Apach 2.0 许可", // 许可
"许可链接", // 许可连接
new ArrayList<>()// 扩展
);
}
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("group1");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("group2");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2).groupName("group3");
}
}
启动类
@SpringBootApplication
@MapperScan("com.xxx.dal")
@ServletComponentScan
@EnableWebMvc
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
MvcConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/");
registry.addResourceHandler("/img/**").addResourceLocations("classpath:/img/");
registry.addResourceHandler("/css/**").addResourceLocations("classpath:/css/");
// 解决swagger无法访问
registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
// 解决swagger的js文件无法访问
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
拦截器配置
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class AuthenticationInterceptorConfig implements WebMvcConfigurer {
// 注入拦截器
@Autowired
AuthenticationInterceptorConfig authenticationInterceptorConfig;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptorConfig).addPathPatterns("/**")
.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/error");
}
}
拦截器
package xxx.interceptor;
import xxx.config.MAPIHttpServletRequestWrapper;
import xxx.dal.operation.dataobject.OperationAppDO;
import xxx.model.func.OperateUserDTO;
import xxx.model.func.UserHolder;
import xxx.service.OperationAppService;
import xxx.service.WhiteListService;
import xxx.util.ApplicationContextUtil;
import xxx.util.CusAccessObjectUtil;
import xxx.util.EncryptionUtil;
import org.apache.commons.net.util.SubnetUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.*;
import static xxx.constant.InterceptorConstant.*;
import static xxx.model.error.OperationErrorEnum.ACCESS_EXPIRE;
import static xxx.model.error.OperationErrorEnum.ACCESS_PARAM_ERROR;
/**
* ip白名单和API鉴权拦截器
*/
@Configuration
public class AuthenticationInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationInterceptor.class);
private static WhiteListService whiteListService;
private static OperationAppService operationAppService;
private WhiteListService getWhitelistService() {
if (Objects.isNull(whiteListService)){
whiteListService = (WhiteListService)ApplicationContextUtil.getBean("whiteListServiceImpl");
}
return whiteListService;
}
private OperationAppService getOperationAppService() {
if (Objects.isNull(operationAppService)){
operationAppService = (OperationAppService)ApplicationContextUtil.getBean("operationAppServiceImpl");
}
return operationAppService;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
String methodName = method.getName();
logger.info("==== AuthenticationInterceptor拦截器拦截到了方法:{},在该方法执行之前执行====", methodName);
// 1、白名单
/* String ipAddress = CusAccessObjectUtil.getIpAddress(request);
List<String> allIp = getWhitelistService().getAllIp();
boolean anyMatch = allIp.stream().anyMatch(ip -> new SubnetUtils(ip).getInfo().isInRange(ipAddress));
if (!anyMatch){
logger.info("==== AuthenticationInterceptor拦截器拦截到了方法:{} 白名单检验不通过 ====", methodName);
return false;
}*/
// 2、校验header中的时间戳,时差不超过5分钟
String timestamp = "";
String sign = "";
String appId = "";
String userId = "";
String name = "";
try {
timestamp = request.getHeader(TIMESTAMP);
sign = request.getHeader(SIGN);
appId = request.getHeader(APPID);
userId = request.getHeader(EMP_ID);
name = request.getHeader(NICK_NAME_CN);
// TODO 需要还原
if ((Math.abs(System.currentTimeMillis() - Long.valueOf(timestamp)) / 1000 / 60) > EXPIRE_TIME) {
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getOutputStream().write(new String(ACCESS_EXPIRE.getErrorDesc()).getBytes(StandardCharsets.UTF_8));
logger.info("==== AuthenticationInterceptor拦截器拦截到了方法:{} 时间戳过期 ====", methodName);
return false;
}
OperateUserDTO user = new OperateUserDTO();
user.setId(userId);
user.setNickName(name);
UserHolder.saveUser(user);
} catch (Exception e) {
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getOutputStream().write(new String(ACCESS_PARAM_ERROR.getErrorDesc()).getBytes(StandardCharsets.UTF_8));
logger.info("==== AuthenticationInterceptor拦截器拦截到了方法:{} 解析鉴权参数异常 ====", methodName);
return false;
}
// 3、校验参数
Map<String, OperationAppDO> operationAppDOMap = getOperationAppService().getAllAppInfo();
if (!operationAppDOMap.containsKey(appId)){
logger.info("==== AuthenticationInterceptor拦截器拦截到了方法:{} 鉴权失败 appId不存在 ====", methodName);
return false;
}
//MAPIHttpServletRequestWrapper解决流不能读两次的问题
Map<String,Object> paramMap = MAPIHttpServletRequestWrapper.getBodyMap(request.getInputStream());
List<String> paramList = new ArrayList<>();
if (!CollectionUtils.isEmpty(paramMap)){
for (String s : paramMap.keySet()) {
paramList.add(paramMap.get(s).toString());
}
}
paramList.add(appId);
paramList.add(timestamp);
paramList.add(operationAppDOMap.get(appId).getAppSecret());
Collections.sort(paramList, String::compareTo);
StringBuilder builder = new StringBuilder();
paramList.forEach(param -> builder.append(param));
String md5 = EncryptionUtil.getMD5(builder.toString());
if (Objects.equals(md5, sign)){
return true;
}
logger.info("==== AuthenticationInterceptor拦截器拦截到了方法:{} 鉴权失败 签名鉴权失败 ====", methodName);
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.info("AuthenticationInterceptor 执行完方法之后进执行(Controller方法调用之后),但是此时还没进行视图渲染");
super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.info("AuthenticationInterceptor 整个请求都处理完咯,DispatcherServlet也渲染了对应的视图咯");
super.afterCompletion(request, response, handler, ex);
}
}