• springcloud+gateway微服务整合swagger


    单一的微服务集成swagger:

    maven:

      <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
           <version>2.9.2</version>     </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId>
           <version>2.9.2</version> </dependency>
    package fwz.cpjiang.ums.utils;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.ParameterBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.schema.ModelRef;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.Parameter;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
    
        @Bean
        public Docket createRestApi(){
            ParameterBuilder tokenPar = new ParameterBuilder();
    
            List<Parameter> pars = new ArrayList<Parameter>();
            tokenPar.name("token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
            pars.add(tokenPar.build());
            return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                    .select()
                    .apis(RequestHandlerSelectors.any())
                    .paths(PathSelectors.any()).build().globalOperationParameters(pars);
        }
    
        private ApiInfo apiInfo(){
            return new ApiInfoBuilder()
                    .title("用户管理 API Doc")
                    .description("This is a restful api document of 用户管理.")
                    .version("1.0")
                    .build();
        }
    
    }

     此时swagger只是存在于单一的微服务,很不方便

    gateway整合swagger:

    所有的微服务均按上述配置swagger

    然后在gateway微服务中,添加如下配置:

    package fwz.cpjiang.gateway.utils;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.swagger.web.SecurityConfiguration;
    import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
    import springfox.documentation.swagger.web.UiConfiguration;
    import springfox.documentation.swagger.web.UiConfigurationBuilder;
    
    @Configuration
    public class SwaggerConfig {
    
        @Bean
        public SecurityConfiguration securityConfiguration() {
            return SecurityConfigurationBuilder.builder().build();
        }
    
        @Bean
        public UiConfiguration uiConfiguration() {
            return UiConfigurationBuilder.builder().build();
        }
    
    }
    package fwz.cpjiang.gateway.utils;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import reactor.core.publisher.Mono;
    import springfox.documentation.swagger.web.*;
    
    import java.util.List;
    import java.util.Optional;
    
    @RestController
    @RequestMapping("/swagger-resources")
    public class SwaggerHandler {
    
        private final SecurityConfiguration securityConfiguration;
        private final UiConfiguration uiConfiguration;
        private final SwaggerResourcesProvider swaggerResources;
    
        @Autowired
        public SwaggerHandler(SwaggerResourcesProvider swaggerResources, SecurityConfiguration securityConfiguration, UiConfiguration uiConfiguration) {
            this.swaggerResources = swaggerResources;
            this.securityConfiguration = securityConfiguration;
            this.uiConfiguration = uiConfiguration;
        }
    
        @GetMapping("/configuration/security")
        public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
            return Mono.just(new ResponseEntity<>(
                    Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()),
                    HttpStatus.OK));
        }
    
        @GetMapping("/configuration/ui")
        public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
            return Mono.just(new ResponseEntity<>(
                    Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
        }
    
        @GetMapping
        public Mono<ResponseEntity<List<SwaggerResource>>> swaggerResources() {
            return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
        }
    
    }
    package fwz.cpjiang.gateway.utils;
    
    import lombok.AllArgsConstructor;
    import org.springframework.cloud.gateway.config.GatewayProperties;
    import org.springframework.cloud.gateway.route.RouteLocator;
    import org.springframework.cloud.gateway.support.NameUtils;
    import org.springframework.context.annotation.Primary;
    import org.springframework.stereotype.Component;
    import springfox.documentation.swagger.web.SwaggerResource;
    import springfox.documentation.swagger.web.SwaggerResourcesProvider;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Primary
    @Component
    @AllArgsConstructor
    public class SwaggerProvider implements SwaggerResourcesProvider {
    
        public static final String API_URI = "/v2/api-docs";
        private final RouteLocator routeLocator;
        private final GatewayProperties gatewayProperties;
    
        @Override
        public List<SwaggerResource> get() {
            List<SwaggerResource> resources = new ArrayList<>();
            List<String> routes = new ArrayList<>();
            routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
            gatewayProperties.getRoutes().stream()
                    .filter(routeDefinition -> routes.contains(routeDefinition.getId()))
                    .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
                            .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                            .forEach(predicateDefinition -> resources
                                    .add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()
                                            .get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", API_URI)))));
            return resources;
        }
    
        private SwaggerResource swaggerResource(String name, String url) {
            SwaggerResource swaggerResource = new SwaggerResource();
            swaggerResource.setName(name);
            swaggerResource.setUrl(url);
            swaggerResource.setSwaggerVersion("2.0");
            return swaggerResource;
        }
    }
    package fwz.cpjiang.gateway.utils;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.List;
    
    @Configuration
    @ConfigurationProperties(prefix = "system")
    public class UrlConfig {
        // 配置文件使用list接收
        private List<String> whiteList;
    
        public List<String> getWhiteList() {
            return whiteList;
        }
        public void setWhiteList(List<String> whiteList) {
            this.whiteList = whiteList;
        }
    }

    yml配置文件:

    system:
      whiteList:
          - "/swagger-ui.html"
          - "/swagger-resources/**"
          - "/v2/api-docs"
          - "/admin/login"
    routes:
    - id: hbistc-ums
    uri: lb://hbistc-ums
    predicates:
    - Path=/ums/**
    filters:
    - StripPrefix=1
    - id: hbistc-mall
    uri: lb://hbistc-mall
    predicates:
    - Path=/mall/**
    filters:
    - StripPrefix=1
    package fwz.cpjiang.gateway.utils;
    
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.JwtBuilder;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Base64;
    import java.util.Date;
    import java.util.UUID;
    
    /**
     * JWT工具类
     */
    public class JwtUtils {
    
        //有效期为
        public static final Long JWT_TTL = 3600000L;// 60 * 60 *1000  一个小时
        //设置秘钥明文
        public static final String JWT_KEY = "joijgisdlwejjjfeawoGdeizeffsaz";
    
        /**
         * 创建token
         *
         * @param id
         * @param subject
         * @param ttlMillis
         * @return
         */
        public static String createJWT(String id, String subject, Long ttlMillis) {
    
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            if (ttlMillis == null) {
                ttlMillis = JwtUtils.JWT_TTL;
            }
            long expMillis = nowMillis + ttlMillis;
            Date expDate = new Date(expMillis);
            SecretKey secretKey = generalKey();
    
            JwtBuilder builder = Jwts.builder()
                    .setId(id)              //唯一的ID
                    .setSubject(subject)   // 主题  可以是JSON数据
                    .setIssuer("admin")     // 签发者
                    .setIssuedAt(now)      // 签发时间
                    .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
                    .setExpiration(expDate);// 设置过期时间
            return builder.compact();
        }
    
        /**
         * 生成加密后的秘钥 secretKey
         *
         * @return
         */
        public static SecretKey generalKey() {
            byte[] encodedKey = Base64.getDecoder().decode(JwtUtils.JWT_KEY);
            SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
            return key;
        }
    
        /**
         * 解析
         *
         * @param jwt
         * @return
         * @throws Exception
         */
        public static Claims parseJWT(String jwt) throws Exception {
            SecretKey secretKey = generalKey();
            return Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jwt)
                    .getBody();
    
        }
    
        public static void main(String[] args) throws Exception {
            String token = createJWT(UUID.randomUUID().toString(), "ggggggg", null);
            System.out.println(token);
            Claims c = parseJWT(token);
            String id = c.getId();
            System.out.println(id);
        }
    }
    package fwz.cpjiang.gateway.filter;
    
    import cn.hutool.core.util.StrUtil;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import fwz.cpjiang.gateway.utils.JwtUtils;
    import fwz.cpjiang.gateway.utils.UrlConfig;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.Ordered;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    import reactor.netty.ByteBufFlux;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 鉴权过滤器 验证token
     */
    
    @Component
    public class AuthorizeFilter implements GlobalFilter, Ordered {
        private static final String AUTHORIZE_TOKEN = "token";
        @Autowired
        private UrlConfig urlConfig;
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            //1. 获取请求
            ServerHttpRequest request = exchange.getRequest();
            //2. 则获取响应
            ServerHttpResponse response = exchange.getResponse();
            //3. 如果是登录请求则放行
            for (int i = 0; i <urlConfig.getWhiteList().size() ; i++) {
                if (request.getURI().getPath().contains(urlConfig.getWhiteList().get(i))) {
                    return chain.filter(exchange);
                }
            }
    
            //4. 获取请求头
            HttpHeaders headers = request.getHeaders();
            //5. 请求头中获取令牌
            String token = headers.getFirst(AUTHORIZE_TOKEN);
    
            //6. 判断请求头中是否有令牌
            if (StrUtil.isEmpty(token)) {
                //7. 响应中放入返回的状态吗, 没有权限访问
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                //8. 返回
                //return response.setComplete();
                //设置响应头信息Content-Type类型
                response.getHeaders().add("Content-Type","application/json");
                //设置返回json数据
                return response.writeAndFlushWith(Flux.just(ByteBufFlux.just(response.bufferFactory().wrap(getWrapData()))));
    
            }
    
            //9. 如果请求头中有令牌则解析令牌
            try {
                JwtUtils.parseJWT(token);
            } catch (Exception e) {
                e.printStackTrace();
                //10. 解析jwt令牌出错, 说明令牌过期或者伪造等不合法情况出现
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                //11. 返回
                //设置响应头信息Content-Type类型
                response.getHeaders().add("Content-Type","application/json");
                //设置返回json数据
                return response.writeAndFlushWith(Flux.just(ByteBufFlux.just(response.bufferFactory().wrap(getWrapData()))));
    
            }
            //12. 放行
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    
        private byte[] getWrapData() {
            Map<String,String> map = new HashMap<>();
            map.put("code","1");
            map.put("msg","token is empty or illegal");
            try {
                return new ObjectMapper().writeValueAsString(map).getBytes();
            } catch (JsonProcessingException e) {
                //
            }
            return "".getBytes();
        }
    }

    进行白名单过滤

    然后访问网关:

     可以发现红框内出现了微服务切换的选项,至此整合完毕

  • 相关阅读:
    JDBCUtils
    C3P0配置
    反射基本常识(二)
    反射基本常识(一)
    String to Integer (atoi)
    ZigZag Conversion
    Longest Palindromic Substring
    Palindrome Number
    Reverse Integer
    Longest Substring Without Repeating Characters
  • 原文地址:https://www.cnblogs.com/fengwenzhee/p/15886870.html
Copyright © 2020-2023  润新知