# 前言

B端系统的访问一般需要进行权限认证,并且只对指定的IP开放。FizzGate原生支持认证方式:MD5签名、密钥认证,支持IP白名单,并且支持通过自定义插件方式定制签名和验签方法。本篇文章介绍FizzGate集成平台中与B端系统接入相关的功能,并且通过一步步操作演示接入一个测试的B端系统。

# appID管理

appID管理功能用于配置应用认证信息,可配置是否启用认证、是否启用IP白名单,AppID级别的自定义配置供自定义插件使用。

# 启用认证

新增appID配置(网关管理 -> appID管理 -> 新增),如下图所示:

b_service_access_app_id_1

点击是否启用认证选项后开启认证,如下图所示:

b_service_access_app_id_2

开启认证后可选择认证方式,支持:

  • MD5签名:调用方需传签名请求头fizz-sign和时间戳请求头fizz-ts,生成MD5签名: MD5(appid++时间戳++密钥)

    b_service_access_app_id_3

  • 密钥认证:调用方需传签名请求头fizz-sign, 值为密钥

    b_service_access_app_id_4

  • 自定义认证插件:自定义插件方式可定制签名和验签方法

    b_service_access_app_id_5

这里我们选择MD5签名认证方式,并随机生成密钥(faa780aaa80c46d68217ba0c3c25736d),如下图所示:

b_service_access_app_id_6

# 启用IP白名单

点击是否启用IP白名单选项后开启IP白名单,如下图所示:

b_service_access_app_id_7

这里我们开启了IP白名单,并且将我开发机器的IP地址加入白名单。

最后保存,完成appID配置。

# 自定义认证插件

FizzGate集成平台支持自定义认证插件,通过自定义认证插件可定制签名和验签方法。

# 插件配置

appID配置可添加自定义配置内容,在自定义认证插件实现内可获取到对应的配置,如下图所示:

b_service_access_auth_plugin_1

# 插件逻辑实现

fizz-gateway-node项目中添加实现we.plugin.auth.CustomAuth接口的实现类,代码逻辑如下:

	@Component(BusinessSignAuthPluginFilter.BUSINESS_SING_AUTH_PLUGIN_FILTER)
	public class BusinessSignAuthPluginFilter implements CustomAuth {
		private static final Logger log = LoggerFactory.getLogger(BusinessSignAuthPluginFilter.class);
		public  static final String BUSINESS_SING_AUTH_PLUGIN_FILTER = "businessSignAuthPlugin";
		@Override
		public Mono<ApiConfigService.Access> auth(ServerWebExchange exchange, String appId, String ip, String timestamp, String sign, App fizzAppConfig) {
			ServerHttpRequest clientReq = exchange.getRequest();
			HttpHeaders hdrs = clientReq.getHeaders();
			if(StringUtils.isBlank(appId)){
				//兼容
				String businessAppId = hdrs.getFirst("app-id");
				appId = businessAppId;
			}
			String customTimestamp=hdrs.getFirst("timestamp");
			String customSign=hdrs.getFirst("sign");
			String customSecretKey=fizzAppConfig.secretkey;
			//是否开启签名
			boolean useAuth=fizzAppConfig.useAuth;
			try {
				if (!StringUtils.isBlank(customTimestamp)) {
					long times = Long.valueOf(customTimestamp);
					if (System.currentTimeMillis() - times > 600000) {
						return Mono.just(ApiConfigService.Access.CUSTOM_AUTH_REJECT);
					}
				}
			}catch (Throwable e) {
				log.error("timestamp error,appId:{},timestamp:{},sign:{}", appId, timestamp, customSign);
				return Mono.just(ApiConfigService.Access.CUSTOM_AUTH_REJECT);
			}


			String sign2;
			try {
				sign2 = DigestUtils.sha256Hex((appId + "-" + customTimestamp + '-' + customSecretKey).getBytes(Charset.forName("UTF-8")));
			} catch (Throwable e) {
				log.error("sign error,appId:{},timestamp:{},sign:{}", appId, timestamp, customSign);
				return Mono.just(ApiConfigService.Access.CUSTOM_AUTH_REJECT);
			}

			boolean checkSign = sign2.equalsIgnoreCase(customSign);
			if (!checkSign && useAuth) {
				log.error("sign error,appId:{},timestamp:{},sign:{},trueSign:{}", appId, timestamp, customSign, sign2);
				return Mono.just(ApiConfigService.Access.CUSTOM_AUTH_REJECT);
			}

			// 获取自定义配置
			String selfConfig = fizzAppConfig.config;
			if(!StringUtils.isBlank(selfConfig)){
				// 使用自定义配置做一些处理
				// Map<String,String> sconfig = JSON.parseObject(selfConfig, Map.class);
				// enterpriseMebId = sconfig.get(NeedLogin.ENTERPRISE_MEB_ID);
				// WebUtils.appendHeader(exchange,NeedLogin.ENTERPRISE_MEB_ID, enterpriseMebId);
			}


			return Mono.just(ApiConfigService.Access.YES);
		}
	}

完成后即可在appID配置中选择自定义认证插件认证方式来启用定制的签名和验签方法。

更多自定义认证插件介绍请查看FizzGate集成平台插件、FizzGate集成平台二次开发等相关文章。

# 路由管理

配置服务或API路由规则,支持服务编排、服务发现、反向代理三种路由类型,支持插件配置。

# 路由配置

新增路由配置(网关管理 -> 路由管理 -> 新增),如下图所示:

b_service_access_api_auth_1

路由配置支持以下路由类型:

  • 服务编排,将请求转发到服务编排接口(服务编排接口在服务编排功能模块下维护,详情查看服务编排相关文章)

b_service_access_api_auth_2

  • 服务发现,当后端服务和网关都接入同一个注册中心(支持Eureka、Nacos)时使用该方式,后端服务名选项罗列所有服务发现的服务名

b_service_access_api_auth_3

  • 反向代理,将请求转发到后端服务器IP/域名和端口

b_service_access_api_auth_4

这里我本地起了一个名为b-service的测试服务,启动端口为8080,上下文为/b-service,提供对外的接口为/b-interface。因此路由配置选用反向代理选项,并且启用调用方(appID)选项开启认证,最终配置如下图所示:

b_service_access_api_auth_5

# 发起请求

测试服务b-service配置文件application.yml如下所示:

server:
  port: 8080
  servlet:
    context-path: /b-service

接口/b-interface实现如下所示:

	@SpringBootApplication
	@RestController
	public class BServiceApplication {

		public static void main(String[] args) {
			SpringApplication.run(BServiceApplication.class, args);
		}

		@RequestMapping("/b-interface")
		public Result bInterface() {
			return Result.builder().code(200).msg("SUCCESS").build();
		}

		@Builder
		@Data
		public static class Result {
			private final Integer code;
			private final String msg;
		}
	}

启动测试服务b-service后通过Postman调用网关接口(我的fizz-gateway-node服务的地址为http://172.25.63.248:8600),接口正常返回,如下图所示:

b_service_access_request_1

其中使用Postman的预处理脚本设置请求头以通过FizzGate集成平台的认证,预处理脚本如下:

	var CryptoJS = require('crypto-js')
	var appId = pm.request.headers.get("fizz-appid");
	var key = pm.request.headers.get("key");
	var timestamp = Date.now();
	pm.environment.set("fizz-ts", timestamp);
	var sign = CryptoJS.MD5(appId + '_' + timestamp + '_' + key).toString()
	pm.environment.set("fizz-sign", sign);

请求头配置如下:

	fizz-appid:test-b-service
	key:faa780aaa80c46d68217ba0c3c25736d
	fizz-ts:{{fizz-ts}}
	fizz-sign:{{fizz-sign}}

至此,我们的测试服务b-service成功接入FizzGate集成平台,外部请求设置正确的请求头信息通过FizzGate的认证,最后正常访问到/b-interface接口。

# 总结

B端系统接入FizzGate集成平台主要使用到了FizzGate集成平台的appID管理路由管理功能,通过FizzGate集成平台的权限认证、IP白名单过滤以及动态路由能力将B端系统服务安全的暴露给第三方对接企业使用。