swagger2帶全局token配置

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;
   }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鉴腻,一起剝皮案震驚了整個(gè)濱河市迷扇,隨后出現(xiàn)的幾起案子百揭,更是在濱河造成了極大的恐慌,老刑警劉巖蜓席,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件器一,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡厨内,警方通過查閱死者的電腦和手機(jī)祈秕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雏胃,“玉大人请毛,你說我怎么就攤上這事〔t亮!?“怎么了方仿?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)街州。 經(jīng)常有香客問我兼丰,道長(zhǎng),這世上最難降的妖魔是什么唆缴? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任鳍征,我火速辦了婚禮,結(jié)果婚禮上面徽,老公的妹妹穿的比我還像新娘艳丛。我一直安慰自己,他們只是感情好趟紊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布氮双。 她就那樣靜靜地躺著,像睡著了一般霎匈。 火紅的嫁衣襯著肌膚如雪戴差。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天铛嘱,我揣著相機(jī)與錄音暖释,去河邊找鬼。 笑死墨吓,一個(gè)胖子當(dāng)著我的面吹牛球匕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播帖烘,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼亮曹,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起照卦,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤式矫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后窄瘟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衷佃,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年蹄葱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了氏义。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡图云,死狀恐怖惯悠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情竣况,我是刑警寧澤克婶,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站丹泉,受9級(jí)特大地震影響情萤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜摹恨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一筋岛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧晒哄,春花似錦睁宰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至较木,卻和暖如春红符,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伐债。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工预侯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泳赋。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓雌桑,卻偏偏與公主長(zhǎng)得像喇喉,于是被迫代替她去往敵國(guó)和親祖今。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容