Swagger怎么做免鉴权

2023-11-08

前言

Swagger在API文档生成及测试方面非常方便,但是很多的API调用都需要用到token验证,然后经过Gateway网关,鉴权验证通过之后访问业务系统。为了方便后端开发自测接口,我们可以免去鉴权吗?答案是可以的!

一般鉴权方式

我们先看看如果需要鉴权,应该怎么做呢?
可以在swagger config类里边使用 globalOperationParameters() 方法来配置全局参数token:

@Configuration
@EnableSwagger2
public class SwaggerConfig {
 
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(Arrays.asList(
                        new ParameterBuilder()
                                .name("token")
                                .description("授权")
                                .modelRef(new ModelRef("string"))
                                .parameterType("header")
                                .required(false)
                                .build()
                ))
                .apiInfo(apiInfo());
    }
 
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("接口文档")
                .description("接口文档")
                .version("1.0.0")
                .build();
    }
 }

也可以使用 securitySchemes() 方法来配置安全协议token:

@Configuration
@EnableSwagger2
public class SwaggerConfig {
 
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
                .paths(PathSelectors.any())
                .build()
                .securitySchemes(Arrays.asList(
                        new ApiKey("Bearer", "token", "header")
                ))
                .apiInfo(apiInfo());
    }
 
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("接口文档")
                .description("接口文档")
                .version("1.0.0")
                .build();
    }
 }

请求头有了token,一般项目的话,请求发到服务端做鉴权,微服务的话,访问服务端之前,需要在Gateway鉴权,我们先了解下什么是Gateway,他的作用又是什么呢。

Gateway是什么?

官方解释Gateway微服务中必不可少的一个组件,旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式,具有参数校验、权限校验、流量监控、日志输出、协议转换、响应内容、响应头修改等功能。
微服务架构图

那我们想想,之前没有微服务的时候,这些功能不是在业务系统里面也能实现吗?为什么现在都要放在Gateway中来呢?没错,为了解耦!业务系统专注于系统本身,网关作为接收客户端请求和业务系统的中间层,这些”杂事“交给Gateway统一管理再合适不过了。

Gateway三大核心

1.Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
2.Predicate(断言):参考的是Java8的java.util.function.Predicate
开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
3.Filter(过滤):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前(pre)或者之后(post)对请求进行修改,目前开放出来的过滤参数有兴趣可以了解下,https://blog.csdn.net/m0_67402096/article/details/126496872。

Gateway配置示例

###########应用配置  start###########
server:
port: 8080

spring:
  cloud:
    gateway:
      routes:
        - id: 39-base
          uri: http://10.43.117.39:8001
          predicates:
            - Path=/39/projectName/**
          filters:
            - StripPrefix=2
            - name: AddUserName
              args:
                enabled: true
                shouldSkipUrls:
                  - /v2/api-docs/**
                  - /swagger-ui.html*
                  - /webjars/**
                  - /actuator/**
                  - /swagger-resources/**
                  - /i18n/**
                  - /login-free/**
                  - /cloud-test/findPrintList*
                  - /persons/resetPassword**
                  - /cloud-test/**
                  - /t-role-apply/apsPlanPageInfo
                  - /IAM-app-user/**
                  - /flotsam/dataTransferBPMPS
                  - /qrCode/**					
###########应用配置  end###########	

解读配置

现在有一个服务39-base部署在本机,地址和端口为10.43.117.39:8081,所以路由配置uri为http://10.43.117.39:8081
使用网关服务路由到此服务,predicates -Path=/39/projectName/**,网关服务的端口为8080,启动网关服务,访问10.43.117.39:8080/39/projectName,路由断言就会将请求路由到39-base。
直接访问39-base的接口10.43.117.39:8081/swagger-ui.html#/api/test,通过网关的访问地址则为10.43.117.39:8080/39/projectName/swagger-ui.html#/api/test,predicates配置将请求断言到此路由,filters-StripPrefix=1代表将地址中/后的第一个截取,所以39/projectName就截取掉了。

那我们知道了,鉴权其实就是一种过滤规则,或者说是校验规则。那怎么做到免鉴权的呢,其实就是在Filter中配置相应的参数,但是目前Gateway没有开放相应的参数,比较好的是,它支持自定义参数,具体是怎么做的呢,我们往下看:
1、配置yml,如上图所示,配置的shouldSkipUrls参数;
2、配置文件:NotAuthUrlPropertie;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.LinkedHashSet;

@Data
@Component
@ConfigurationProperties("agilepay.gateway")
public class NotAuthUrlProperties {

    private LinkedHashSet<String> shouldSkipUrls;
}

3、重写GlobalFilter.Filter方法。(Gateway提供GlobalFilter(实现过滤器业务)及Ordered(定义过滤器执行顺序)两个接口用来定义过滤器,我们自定义过滤器只需要实现这个两个接口即可。)

@Component
@Slf4j
public class WrapperRequestGlobalFilter implements GlobalFilter, Ordered {//, Ordered
    @Autowired
    private RsaKeyMapper rsaKeyMapper;

    @Resource
    private NotAuthUrlProperties notAuthUrlProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String currentUrl = exchange.getRequest().getURI().getPath();

        //1:不需要认证的url,不过滤放行的url
        if (shouldSkip(currentUrl)) {
            log.info("==========已跳过url{}=====", currentUrl);
            return chain.filter(exchange);
        }
        log.info("===========网关请求解密开始==================");
        return exchange.getResponse().setComplete();
    }


    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 方法实现说明:不需要过滤的路径
     * <p>
     * //     * @param currentUrl 当前请求路径
     */
    private boolean shouldSkip(String currentUrl) {
        PathMatcher pathMatcher = new AntPathMatcher();
        for (String skipPath : notAuthUrlProperties.getShouldSkipUrls()) {
            if (pathMatcher.match(skipPath, currentUrl)) {
                return true;
            }
        }
        return false;
    }
}

使用gateway通过配置文件即可完成路由的配置,非常方便,我们只要充分的了解配置项的含义及规则就可以了;但是这些配置如果要修改则需要重启服务,重启网关服务会导致整个系统不可用,这一点是无法接受的,下面介绍如何通过Nacos实现动态路由。
使用nacos结合gateway-server实现动态路由,我们需要先部署一个nacos服务,可以使用docker部署或下载源码在本地启动,具体操作可以参考官方文档即可。

Nacos_Gateway配置

在这里插入图片描述
Nacos实现动态路由的方式核心就是通过Nacos配置监听,配置发生改变后执行网关相关api创建路由
在这里插入图片描述

Nacos配置监听

@Component
public class NacosDynamicRouteService implements ApplicationEventPublisherAware {
private static final Logger LOGGER = LoggerFactory.getLogger(NacosDynamicRouteService.class);

@Autowired
private RouteDefinitionWriter routeDefinitionWriter;

private ApplicationEventPublisher applicationEventPublisher;

/** 路由id */
private static List<String> routeIds = Lists.newArrayList();

/**
 * 监听nacos路由配置,动态改变路由
 * @param configInfo
 */
@NacosConfigListener(dataId = "routes", groupId = "gateway-server")
public void routeConfigListener(String configInfo) {
    clearRoute();
    try {
        List<RouteDefinition> gatewayRouteDefinitions = JSON.parseArray(configInfo, RouteDefinition.class);
        for (RouteDefinition routeDefinition : gatewayRouteDefinitions) {
            addRoute(routeDefinition);
        }
        publish();
        LOGGER.info("Dynamic Routing Publish Success");
    } catch (Exception e) {
        LOGGER.error(e.getMessage(), e);
    }
    
}


/**
 * 清空路由
 */
private void clearRoute() {
    for (String id : routeIds) {
        routeDefinitionWriter.delete(Mono.just(id)).subscribe();
    }
    routeIds.clear();
}

@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    this.applicationEventPublisher = applicationEventPublisher;
}

/**
 * 添加路由
 * 
 * @param definition
 */
private void addRoute(RouteDefinition definition) {
    try {
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        routeIds.add(definition.getId());
    } catch (Exception e) {
        LOGGER.error(e.getMessage(), e);
    }
}

/**
 * 发布路由、使路由生效
 */
private void publish() {
    this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
}
}

总结

Swagger免鉴权是重写了Gateway中GlobalFilter接口Filter方法,方法中用当前请求url和配置免鉴权的url做匹配,匹配到则免鉴权;整合Nacos及配置监听就可以实现动态路由了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Swagger怎么做免鉴权 的相关文章

  • 使用 java 从 XML 元素中删除空格

    我有一个 JSON 如下 String str Emp name JSON Emp id 1 Salary 20997 00 我想使用 java 将此 JSON 转换为 XML 我的 java 代码在这里 JSON json JSONSer
  • HibernateTemplate 可以与 EntityManager 共存吗?

    我们有一个 spring 3 应用程序 它仍然使用已弃用的HibernateTemplate为了持久性并希望迁移到更现代的 JPAEntityManager 是否可以在迁移过程中并行使用这两个 API 甚至可能在单个事务中同时使用 以便我们
  • 无法执行目标 org.codehaus.mojo:exec-maven-plugin:1.5.0:exec

    三周前 我完成了一个网络应用程序的工作 一切都运行没有问题 现在 三周后 没有任何更改 我想再次运行该应用程序 但这次我收到以下错误消息 An error occurred while parsing the server response
  • 如何使用 Jsoup 获取包含非 ASCII 字符(ą、ś ...)的 URL?

    我正在使用 jsoup 解析一些波兰网站 但我对 URL 中的 等特殊字符有问题example com k t读起来像example com k 每个没有这个特殊字符的查询都可以完美运行 我努力了Document doc Jsoup par
  • Google API - 重定向 URI 不匹配错误

    我正在我的网络应用程序上实现 google 登录 我通过参考this尝试过link https developers google com web signin server side flow 我的 google 登录按钮如下 div s
  • 在 Java 中将字符串复制到文件的开头

    我想将一个字符串写入文件的开头 我该怎么做 我根本不知道如何添加字符串 这就是我到目前为止所做的 public static void prepend String filename String data throws IOExcepti
  • Spring MVC 和 Struts MVC 之间的区别 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 Spring MVC 和 Struts MVC 之间的主要区别是什么 Spring MVC 和 Struts 之间的主要区别是 Spr
  • 如何用 Java 制作 Windows 7 工具提示

    我一直在网上到处寻找 但没有找到这个小问题的答案 在 Windows 7 中 我认为在 Vista 中 您有一个漂亮的圆形银色工具提示 它看起来比旧的黄色盒装蹩脚工具提示要好得多 下面的 How do I make a Windows 7
  • 在 Selenium Grid 中注册 PhantomJS 节点时出错

    我有以下问题 我成功启动了 Selenium Grid hub java jar selenium server standalone 2 53 0 jar role hub 之后我尝试使用以下命令启动 PhantomJS 节点 phant
  • 控制启动时的竞争条件

    我有一些代码想要执行一些一次性初始化 但这段代码没有明确的生命周期 因此在初始化完成之前 我的逻辑可能会被多个线程调用 所以 我想基本上确保我的逻辑代码 等待 直到初始化完成 这是我的第一次剪辑 public class MyClass p
  • 如何在 WebSphere Liberty Batch 中配置事务超时?

    的作用是什么javax transaction global timeout 我是否需要实施检查点 超时 中的方法检查点算法 服务器配置级别有什么东西吗 它如何与应用程序级别的设置进行交互 2016年12月2日编辑 重新设计并解释了为应用程
  • Jetty 提供静态内容所需的最少文件集?

    背景 免责声明 I have veryJava 经验很少 我们之前在 Ant 构建期间使用了 Jetty 6 的包装版本来处理按需静态内容 JS CSS 图像 HTML 因此我们可以使用 PhantomJS 针对 HTTP 托管环境运行单元
  • CompletableFuture SupplyAsync

    我刚刚开始探索 Java 8 的一些并发特性 让我有点困惑的一件事是这两个静态方法 CompletableFuture
  • 在Linux中执行jar文件[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我创建了一个可执行的 Java jar 文件 也就是说 我将 java 程序正确打包到 jar 文件中 包括 META INF MANIFEST 文件
  • 谷歌的Json解析Gson库:JsonElement和JsonObject有什么区别?

    public abstract class JsonElement extends Object 表示 Json 元素的类 它可以是 JsonObject JsonArray JsonPrimitive 或 JsonNull public
  • 如何根据受保护的 String doInBackground 方法中 AsyncTask 的结果调用 Toast.makeText() ?

    我从 AsyncTask 中的数据库中获取数据 如果它为空 我想吐司一个警告文本 我在 AsyncTask 中尝试过 但我了解到它不是在工作线程中调用的 这是我的 doInBackground 方法 protected String doI
  • 在服务器上创建 Zip 文件并使用 java 下载该 zip

    我从 mkyong 获得了以下代码 用于在本地压缩文件 但是 我的要求是在服务器上压缩文件并需要下载它 任何人都可以帮忙吗 代码写入zip文件 public void zipFiles File contentFile File navFi
  • 在 x64 系统上使用 skype-java-api

    我正在使用 skype java api 在 Java 中使用 Skype 我需要的唯一功能是点击即可拨打电话号码 它在 Windows XP x86 上运行良好 但我刚刚在 Windows 7 x64 上测试它 但失败了 错误是 线程 T
  • 在android中测量不规则多边形的面积

    我正在开发一个应用程序 在其中我在地图上绘制多边形 并且我使用的地图不是谷歌 它的Mapsforge开源离线地图库 我可以通过将地理点转换为像素点来轻松在地图上绘制多边形 但在这里我想发现是不规则的多边形 为此我做了很多尝试 但它让我失败了
  • Java编程编译jar

    我有一个文本文件中的java源代码 必须在源代码中输入一些自定义的硬编码变量 然后将其转换为 jar 这是可行的 但是当我运行 jar 时 找不到 Main 类 当我用 WinRAR 解压 jar 文件时 我似乎找不到错误 当我通过 cmd

随机推荐