Background
swagger2輔助后臺(tái)開發(fā)非常方便诞外。但正常使用時(shí)澜沟,我們的接口需要登陸后才能訪問的。即訪問接口時(shí)峡谊,要傳一個(gè)登陸后的token茫虽。那這個(gè)怎么設(shè)置,才可以讓所有接口都允許登陸后訪問呢既们。通常有兩個(gè)方法濒析,加在接口上,訪問每個(gè)接口都需要傳token驗(yàn)證贤壁,我為了方便,采用的是另一種方法埠忘,配置一個(gè)全局的token脾拆,驗(yàn)證后就可以訪問所有接口,如下圖所示
image.png
具體配置如下
- SwaggerConfig
package com.cloudansys.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
/**
* Swagger配置
*
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Value("${project.version:}")
private String version;
@Bean
public Docket systemAPI() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("系統(tǒng)管理")
.description("包括用戶管理莹妒、仿真參數(shù)和告警閾值設(shè)置")
.version(version)
.build())
.groupName("系統(tǒng)管理")
.enable(true)
.select()
// 設(shè)置需要被掃描的類名船,這里設(shè)置為添加了@Api注解的類
.apis(RequestHandlerSelectors.basePackage("com.cloudansys.api.system"))
.paths(PathSelectors.any())
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
@Bean
public Docket routineAPI() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("日常管理")
.description("包括告警和設(shè)備管理")
.version(version)
.build())
.groupName("日常管理")
.enable(true)
.select()
.apis(RequestHandlerSelectors.basePackage("com.cloudansys.api.routine"))
.paths(PathSelectors.any())
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
@Bean
public Docket simulationAPI() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("仿真分析")
.description("包括壓力仿真和流量仿真")
.version(version)
.build())
.groupName("仿真分析")
.enable(true)
.select()
.apis(RequestHandlerSelectors.basePackage("com.cloudansys.api.simulation"))
.paths(PathSelectors.any())
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
@Bean
public Docket LeakPRAPI() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("漏損分析")
.description("漏損概率分析")
.version(version)
.build())
.groupName("漏損分析")
.enable(true)
.select()
.apis(RequestHandlerSelectors.basePackage("com.cloudansys.api.analysis.leak"))
.paths(PathSelectors.any())
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
@Bean
public Docket PipeBrokerPRAPI() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("爆管分析")
.description("爆管概率分析")
.version(version)
.build())
.groupName("爆管分析")
.enable(true)
.select()
.apis(RequestHandlerSelectors.basePackage("com.cloudansys.api.analysis.blast"))
.paths(PathSelectors.any())
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
@Bean
public Docket StatisticsAPI() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("數(shù)據(jù)統(tǒng)計(jì)")
.description("數(shù)據(jù)統(tǒng)計(jì)")
.version(version)
.build())
.groupName("數(shù)據(jù)統(tǒng)計(jì)")
.enable(true)
.select()
.apis(RequestHandlerSelectors.basePackage("com.cloudansys.api.analysis.statistics"))
.paths(PathSelectors.any())
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
@Bean
public Docket TestDataAPI() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("測(cè)試數(shù)據(jù)")
.description("測(cè)試數(shù)據(jù)")
.version(version)
.build())
.groupName("測(cè)試數(shù)據(jù)")
.enable(true)
.select()
.apis(RequestHandlerSelectors.basePackage("com.cloudansys.api.testdata"))
.paths(PathSelectors.any())
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
private List<ApiKey> securitySchemes() {
return newArrayList(
new ApiKey("token", "token", "header"));
}
private List<SecurityContext> securityContexts() {
return newArrayList(
SecurityContext.builder()
.securityReferences(defaultAuth())
// 所有包含"auth"的接口不需要使用securitySchemes
.forPaths(PathSelectors.regex("^(?!auth).*$"))
.build()
);
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return newArrayList(
new SecurityReference("token", authorizationScopes));
}
}
- SwaggerInterceptorConfig
package com.cloudansys.config;
import com.cloudansys.interceptor.SwaggerInterceptor;
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;
/**
* Swagger攔截器配置
*/
@Configuration
public class SwaggerInterceptorConfig implements WebMvcConfigurer {
@Autowired
private SwaggerInterceptor swaggerInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(swaggerInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
}
}
- SwaggerInterceptor
package com.cloudansys.interceptor;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.cloudansys.core.annotation.PassToken;
import com.cloudansys.core.annotation.UserLoginToken;
import com.cloudansys.core.model.ApiResponse;
import com.cloudansys.dao.system.model.UserVO;
import com.cloudansys.exception.ApiException;
import com.cloudansys.exception.ApiExceptionCode;
import com.cloudansys.service.system.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
/**
* Swagger攔截器
*/
@Slf4j
@Component
public class SwaggerInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
@Value("${swagger.enabled:false}")
private Boolean enabledSwagger;
@Value("${swagger.redirect-uri:/}")
private String redirectUri;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!enabledSwagger) {
String uri = request.getContextPath();
if (StringUtils.isNotBlank(redirectUri))
uri = request.getContextPath() + redirectUri;
if (StringUtils.isBlank(uri))
uri = "/";
try {
response.sendRedirect(uri);
} catch (IOException e) {
throw new ApiException(ApiExceptionCode.FORBIDDEN.getCode(), ApiExceptionCode.FORBIDDEN.getMsg());
}
return Boolean.FALSE;
}
// 從 http 請(qǐng)求頭中取出 token
String token = request.getHeader("token");
// 如果不是映射到方法直接通過
if(!(handler instanceof HandlerMethod)){
// log.info("如果不是映射到方法直接通過");
return true;
}
HandlerMethod handlerMethod=(HandlerMethod)handler;
Method method=handlerMethod.getMethod();
// log.info("method: {}", method);
//檢查是否有 PassToken 注釋,有則跳過認(rèn)證
if (method.isAnnotationPresent(PassToken.class)) {
PassToken passToken = method.getAnnotation(PassToken.class);
if (passToken.required()) {
// log.info("檢查是否有 PassToken 注釋旨怠,有則跳過認(rèn)證");
return true;
}
}
//檢查有沒有需要用戶權(quán)限的注解
if (method.isAnnotationPresent(UserLoginToken.class)) {
// log.info("檢查有沒有需要用戶權(quán)限的注解");
UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
if (userLoginToken.required()) {
// 執(zhí)行認(rèn)證
if (null == token) {
throw new ApiException(ApiExceptionCode.UNAUTHORIZED.getCode(), "無 token渠驼,請(qǐng)重新登錄");
}
// 獲取 token 中的 user id
Integer userId;
try {
userId = Integer.valueOf(JWT.decode(token).getAudience().get(0));
} catch (JWTDecodeException j) {
throw new ApiException(ApiExceptionCode.UNAUTHORIZED.getCode(), "token 解析錯(cuò)誤");
}
UserVO user = userService.getByUserId(userId);
if (user == null) {
throw new ApiException(ApiExceptionCode.UNAUTHORIZED.getCode(), "無 token,請(qǐng)重新登錄");
}
// 驗(yàn)證 token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new ApiException(ApiExceptionCode.UNAUTHORIZED.getCode(), "token 驗(yàn)證錯(cuò)誤");
}
return true;
}
}
return Boolean.FALSE;
}
}