IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringCloud下关于SWAGGER2的部署包含JWT+GATEWAY鉴权 -> 正文阅读

[Java知识库]SpringCloud下关于SWAGGER2的部署包含JWT+GATEWAY鉴权

BackGround-背景

Recently, I am coding a Spring Cloud project, that I need to test something with Swagger.The problem is that I need to route and filter the request urls of Swagger in case of being block by JWT Auth & Gateway Custom Filter.

最近,我在做一个微服务项目,需要用到Swagger。问题是我需要路由过滤请求,防止他被JWT和网关自定义过滤器给阻挡。

Project Structure 项目结构

There are 2 consumers modules and 1 gateway module in this project.

这有2个消费者 和1个生产者。

img

Process-过程

Add depencies of swagger2 & ui to commons module.Here I use version-2.9.2

  1. Add Maven dependencies of swagger2 & ui to commons module.Here I use version-2.9.2.

在commons模块添加swagger2和ui的Maven依赖,这里我使用的版本是-2.9.2.

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

img


  1. Create SwaggerConfig.java to admin & app-server modules.At the same time,don’t forget to add urls pattern of Swagger including its urls static urls to the interceptors to make it free to be visited without token as we make token interceptor for authorization.

在admin和app-server模块下添加SwaggerConfig.java配置类。与此同时,由于我们做了token认证的拦截器,别忘记把swagger的访问的路径,包括他的静态文件路径到拦截器里排除掉,使他们能够被正常访问。

img

package com.tanhua.admin.config;

import lombok.extern.slf4j.Slf4j;
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.Contact;
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;

/**
 * @Description: SwaggerCongig配置
 * @Author: Spike Wong
 * @Date: 2022/9/8
 */
@Slf4j
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    private boolean SWAGGER_IS_ENABLE = true;

    /**
     * 创建文档接口信息
     *
     * @return
     */
    public ApiInfo createApiInfo() {
        return new ApiInfoBuilder()
                .title("鸡你太美-交友Admin后端文档")
                .description("陌生人交友")
                .contact(new Contact("ikun探花交友论坛", "tanhua.com", "tanhua@tanhua.com"))
                .version("1.0.0").build();
    }

    /**
     * ioc 容器 存储bean
     *
     * @return
     */
    @Bean
    public Docket createApi() {
        //加token的
        ParameterBuilder tokenPar = new ParameterBuilder();
        List<Parameter> pars = new ArrayList<>();
        tokenPar.name("token").description("token")
                .modelRef(new ModelRef("string")).parameterType("header").required(false).build();
        pars.add(tokenPar.build());
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(SWAGGER_IS_ENABLE)
                .apiInfo(createApiInfo()).select()
            // 根据api所在的包自行替换
            .apis(RequestHandlerSelectors.basePackage("com.tanhua.admin.controller"))
                .paths(PathSelectors.any())
                .build().globalOperationParameters(pars);//全局带token
        //.apis(RequestHandlerSelectors.basePackage(""))//扫描
        //.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
        //                .paths(PathSelectors.any())
    }
}

img

package com.tanhua.server.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Description: 注册拦截器
 * @Author: Spike Wong
 * @Date: 2022/8/9
 */

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/**").excludePathPatterns(new String[]{"/user/login", "/user/loginVerification", "/v2/**", "/webjars/**", "/swagger-ui.html", "/swagger-resources/**"});
        //先把"/**" 所有加进来,再进行逐个排除;
    }
}

  1. In gate-way module, create an api for the visit.Also,we create a SwaggerConfig to configura some properties of Swagger.

在gate-way模块里,增加一个API文件方便访问。我们也创建一个SwaggerConfig 来配置Swagger的属性

img

package com.tanhua.gateway.api;


import com.tanhua.gateway.config.SwaggerConfig;
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.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;

import java.util.Optional;

@RestController
public class SwaggerController {

    @Autowired(required = false)
    private SecurityConfiguration securityConfiguration;

    @Autowired(required = false)
    private UiConfiguration uiConfiguration;

    @Autowired
    private SwaggerConfig swaggerResources;

    @Autowired
    public SwaggerController(SwaggerConfig swaggerResources) {
        this.swaggerResources = swaggerResources;
    }


    @GetMapping("/swagger-resources/configuration/security")
    public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    @GetMapping("/swagger-resources/configuration/ui")
    public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    @GetMapping("/swagger-resources")
    public Mono<ResponseEntity> swaggerResources() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }

    @GetMapping("/")
    public Mono<ResponseEntity> swaggerResourcesN() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }

    @GetMapping("/csrf")
    public Mono<ResponseEntity> swaggerResourcesCsrf() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }
}
package com.tanhua.gateway.config;

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.Configuration;
import org.springframework.context.annotation.Primary;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.ArrayList;
import java.util.List;

@Configuration
@Primary
public class SwaggerConfig implements SwaggerResourcesProvider {
    public static final String API_URI = "/v2/api-docs";
//    public static final String API_URI = "/doc.html";
    private final RouteLocator routeLocator;
    private final GatewayProperties gatewayProperties;

    public SwaggerConfig(RouteLocator routeLocator, GatewayProperties gatewayProperties) {
        this.routeLocator = routeLocator;
        this.gatewayProperties = gatewayProperties;
    }


    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        //取出gateway的route
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        //结合配置的route-路径(Path),和route过滤,只获取有效的route节点
        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 location) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        return swaggerResource;
    }

}

  1. Modify AuthFilter to filter the Swagger Urls & Add the urls in Config list of Nacos

在AuthFilter认证过滤中,过滤掉Swagger的链接,与此同时在Nacos配置中心加入这些urls.

img

img

package com.tanhua.gateway.filters;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tanhua.commons.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description:  认证过滤器,主要是Token的校验
 * @Author: Spike Wong
 * @Date: 2022/8/27
 */
@Component
@Slf4j
@RefreshScope
public class AuthFilter implements GlobalFilter, Ordered {

    @Value("${gateway.excludedUrls}")
    private List<String> excludedUrls;

    @Value("${gateway.swaggerUrls}")
    private List<String> swaggerUrls;


    /**
     * 过滤规则
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.排除不需要校验的链接
        String path = exchange.getRequest().getURI().getPath();
        log.info("请求路径path:{}",path);
        log.info("gateway.excludedUrls:{},-----gateway.swaggerUrls:{}",excludedUrls,swaggerUrls);
        //排除swagger
        if (isAllowPath(path)){
            //先确认是不是swagger的
            return chain.filter(exchange);
        }
        if (excludedUrls.contains(path)) {
            return chain.filter(exchange);
        }

        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        log.info("gateway校验:token:{}",token);
        if (!StringUtils.isEmpty(token)) {
            token=token.replaceFirst("Bearer ", "");
        }
        log.info("处理后的token:{}",token);
        //校验是否异常
        boolean verifyToken = JwtUtils.verifyToken(token);
        log.info("认证后的boolean值:{}",verifyToken);
        //
        if (!verifyToken) {
            Map<String, Object> responseData = new HashMap<>();
            responseData.put("errCode", 401);
            responseData.put("errMessage", "用户未登录");
            return responseError(exchange.getResponse(), responseData);
        }
        //
        return chain.filter(exchange);
    }


    /**
     * 顺序
     * @return
     */
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

    /**
     * 响应错误数据
     * @param response
     * @param responseData
     * @return
     */
    private Mono<Void> responseError(ServerHttpResponse response, Map<String, Object> responseData) {
        // 将信息转换为 JSON
        ObjectMapper objectMapper = new ObjectMapper();
        byte[] data = new byte[0];
        try {
            data = objectMapper.writeValueAsBytes(responseData);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        // 输出错误信息到页面
        DataBuffer buffer = response.bufferFactory().wrap(data);
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));
    }


    /**
     * 遍历白名单
     * @param path
     * @return
     */
    private boolean isAllowPath(String path) {
        //遍历白名单
        for (String allowPath : excludedUrls) {
            //判断是否允许
            if(path.startsWith(allowPath)){
                return true;
            }
        }
        return  false;
    }

}
  1. Finally,we can open the visit url to browse APIs after we start the service of Spring Cloud.

最后,我们可以带链接访问这些APIs

img

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 10:59:34  更:2022-09-13 11:01:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 12:16:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码