欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

swagger2带全局token配置

程序员文章站 2022-03-16 16:30:57
...

Background

swagger2辅助后台开发非常方便。但正常使用时,我们的接口需要登陆后才能访问的。即访问接口时,要传一个登陆后的token。那这个怎么设置,才可以让所有接口都允许登陆后访问呢。通常有两个方法,加在接口上,访问每个接口都需要传token验证,我为了方便,采用的是另一种方法,配置一个全局的token,验证后就可以访问所有接口,如下图所示

swagger2带全局token配置

具体配置如下

  • 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("系统管理")
                        .description("包括用户管理、仿真参数和告警阈值设置")
                        .version(version)
                        .build())
                .groupName("系统管理")
                .enable(true)
                .select()
                // 设置需要被扫描的类,这里设置为添加了@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("包括告警和设备管理")
                        .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("数据统计")
                        .description("数据统计")
                        .version(version)
                        .build())
                .groupName("数据统计")
                .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("测试数据")
                        .description("测试数据")
                        .version(version)
                        .build())
                .groupName("测试数据")
                .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 请求头中取出 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 注释,有则跳过认证
       if (method.isAnnotationPresent(PassToken.class)) {
           PassToken passToken = method.getAnnotation(PassToken.class);
           if (passToken.required()) {
//                log.info("检查是否有 PassToken 注释,有则跳过认证");
               return true;
           }
       }

       //检查有没有需要用户权限的注解
       if (method.isAnnotationPresent(UserLoginToken.class)) {
//            log.info("检查有没有需要用户权限的注解");
           UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
           if (userLoginToken.required()) {
               // 执行认证
               if (null == token) {
                   throw new ApiException(ApiExceptionCode.UNAUTHORIZED.getCode(), "无 token,请重新登录");
               }
               // 获取 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 解析错误");
               }
               UserVO user = userService.getByUserId(userId);
               if (user == null) {
                   throw new ApiException(ApiExceptionCode.UNAUTHORIZED.getCode(), "无 token,请重新登录");
               }
               // 验证 token
               JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
               try {
                   jwtVerifier.verify(token);
               } catch (JWTVerificationException e) {
                   throw new ApiException(ApiExceptionCode.UNAUTHORIZED.getCode(), "token 验证错误");
               }
               return true;
           }
       }
       return Boolean.FALSE;
   }

}