diff --git a/blade-service/blade-system/src/main/resources/application.yml b/blade-service/blade-system/src/main/resources/application.yml index 1d8d630..2d04e41 100644 --- a/blade-service/blade-system/src/main/resources/application.yml +++ b/blade-service/blade-system/src/main/resources/application.yml @@ -32,3 +32,8 @@ iam: authorization: ${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=} profile-authorization: ${IAM_SSO_PROFILE_AUTHORIZATION:YjNlZmU0ODEwMzJiNGJhZTpkYzQ5NDY1NmQ4MzE0NThjODI5MzlmNzA2ZjliNDY3MQ==} page-size: ${IAM_SSO_ACCOUNT_PAGE_SIZE:50} + +# OA人员同步走同一 gwzh 网关,仅需 Authorization(与可用 curl 一致) +thirdParty: + oa: + authorization: ${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}} diff --git a/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/config/OAFeignClientConfig.java b/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/config/OAFeignClientConfig.java index 8917a2d..ef4306a 100644 --- a/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/config/OAFeignClientConfig.java +++ b/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/config/OAFeignClientConfig.java @@ -1,42 +1,26 @@ package org.springblade.thirdparty.oa.config; import feign.Request; -import feign.RequestInterceptor; -import jakarta.annotation.Resource; -import org.springblade.core.tool.utils.StringUtil; +import org.springblade.thirdparty.oa.interceptor.OARequestInterceptor; import org.springframework.context.annotation.Bean; import java.util.concurrent.TimeUnit; /** + * OA Feign 客户端配置 + * * @author bfhuange * @since 2024/12/18 */ public class OAFeignClientConfig { - @Resource - OAProperties oaProperties; - @Bean - public RequestInterceptor requestInterceptor() { - return template -> { - // 空实现屏蔽 全局拦截器 BladeFeignRequestInterceptor - template.header("Authorization", normalizeAuthorization(oaProperties.getAuthorization())); - }; - } + @Bean + public OARequestInterceptor requestInterceptor(OAProperties oaProperties) { + return new OARequestInterceptor(oaProperties); + } @Bean public Request.Options options() { return new Request.Options(10, TimeUnit.SECONDS, 120, TimeUnit.SECONDS, true); } - - private String normalizeAuthorization(String authorization) { - if (StringUtil.isBlank(authorization)) { - return authorization; - } - if (StringUtil.startsWithIgnoreCase(authorization, "Basic ") - || StringUtil.startsWithIgnoreCase(authorization, "Bearer ")) { - return authorization; - } - return "Basic " + authorization; - } } diff --git a/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/config/OAProperties.java b/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/config/OAProperties.java index bfcbae1..264d15b 100644 --- a/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/config/OAProperties.java +++ b/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/config/OAProperties.java @@ -17,7 +17,7 @@ public class OAProperties { private String baseUrl; /** - * authorization + * gwzh 网关 Authorization(Basic),与可用 curl 一致 */ private String authorization; } diff --git a/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/interceptor/OARequestInterceptor.java b/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/interceptor/OARequestInterceptor.java new file mode 100644 index 0000000..fa6e580 --- /dev/null +++ b/blade-third-party-api/blade-oa-api/src/main/java/org/springblade/thirdparty/oa/interceptor/OARequestInterceptor.java @@ -0,0 +1,122 @@ +/** + * BladeX Commercial License Agreement + * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved. + *

+ * Use of this software is governed by the Commercial License Agreement + * obtained after purchasing a license from BladeX. + *

+ * 1. This software is for development use only under a valid license + * from BladeX. + *

+ * 2. Redistribution of this software's source code to any third party + * without a commercial license is strictly prohibited. + *

+ * 3. Licensees may copyright their own code but cannot use segments + * from this software for such purposes. Copyright of this software + * remains with BladeX. + *

+ * Using this software signifies agreement to this License, and the software + * must not be used for illegal purposes. + *

+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is + * not liable for any claims arising from secondary or illegal development. + *

+ * Author: Chill Zhuang (bladejava@qq.com) + */ +package org.springblade.thirdparty.oa.interceptor; + +import feign.RequestInterceptor; +import feign.RequestTemplate; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springblade.core.tool.utils.StringUtil; +import org.springblade.thirdparty.oa.config.OAProperties; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +/** + * OA Feign 请求拦截器。 + *

+ * 对齐可用 curl:仅发送 Authorization + Content-Type,并清掉登录请求透传头, + * 避免 nginx 因 Host/Content-Length/Blade-Auth 等返回 400。 + * + * @author Chill + */ +@Slf4j +@RequiredArgsConstructor +public class OARequestInterceptor implements RequestInterceptor { + + private static final String BASIC_PREFIX = "Basic "; + private static final String BEARER_PREFIX = "Bearer "; + private static final Set STRIP_HEADERS = Set.of( + HttpHeaders.HOST.toLowerCase(Locale.ROOT), + HttpHeaders.CONTENT_LENGTH.toLowerCase(Locale.ROOT), + HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ROOT), + HttpHeaders.ACCEPT.toLowerCase(Locale.ROOT), + HttpHeaders.CONNECTION.toLowerCase(Locale.ROOT), + HttpHeaders.TRANSFER_ENCODING.toLowerCase(Locale.ROOT), + HttpHeaders.COOKIE.toLowerCase(Locale.ROOT), + HttpHeaders.AUTHORIZATION.toLowerCase(Locale.ROOT), + HttpHeaders.ACCEPT_ENCODING.toLowerCase(Locale.ROOT), + HttpHeaders.ORIGIN.toLowerCase(Locale.ROOT), + HttpHeaders.REFERER.toLowerCase(Locale.ROOT), + HttpHeaders.EXPECT.toLowerCase(Locale.ROOT), + "keep-alive", + "upgrade", + "te", + "trailer", + "forwarded", + "x-real-ip", + "x-request-id", + "blade-auth", + "blade-requested-with", + "tenant-id", + "auth" + ); + + private final OAProperties oaProperties; + + @Override + public void apply(RequestTemplate template) { + stripForwardedHeaders(template); + // 与可用 curl 保持一致:Authorization + Content-Type + template.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + + String authorization = normalizeAuthorization(oaProperties.getAuthorization()); + if (StringUtil.isNotBlank(authorization)) { + template.header(HttpHeaders.AUTHORIZATION, authorization); + } else { + log.warn("OA Feign 未配置 third-party.oa.authorization,gwzh 网关可能拒绝请求"); + } + } + + private void stripForwardedHeaders(RequestTemplate template) { + List headerNames = new ArrayList<>(template.headers().keySet()); + for (String headerName : headerNames) { + String lowerName = headerName.toLowerCase(Locale.ROOT); + if (STRIP_HEADERS.contains(lowerName) + || lowerName.startsWith("x-forwarded-") + || lowerName.startsWith("blade-") + || lowerName.startsWith("x-b3-") + || lowerName.startsWith("sw8")) { + template.removeHeader(headerName); + } + } + } + + private String normalizeAuthorization(String authorization) { + if (StringUtil.isBlank(authorization)) { + return authorization; + } + if (StringUtil.startsWithIgnoreCase(authorization, BASIC_PREFIX) + || StringUtil.startsWithIgnoreCase(authorization, BEARER_PREFIX)) { + return authorization; + } + return BASIC_PREFIX + authorization; + } +} diff --git a/doc/nacos/blade-dev.yaml b/doc/nacos/blade-dev.yaml index 562e977..a2763a4 100644 --- a/doc/nacos/blade-dev.yaml +++ b/doc/nacos/blade-dev.yaml @@ -88,6 +88,7 @@ thirdParty: # OA开放接口地址 baseUrl: http://127.0.0.1:8080 queryPersonPageUrl: /gwzh/OA/OA_GET_USER_LIST + authorization: ${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}} track: # 轨迹开放接口地址 baseUrl: http://127.0.0.1:8080 diff --git a/doc/nacos/blade-prod.yaml b/doc/nacos/blade-prod.yaml index 69b2ffa..7279339 100644 --- a/doc/nacos/blade-prod.yaml +++ b/doc/nacos/blade-prod.yaml @@ -60,6 +60,7 @@ thirdParty: # OA开放接口地址 baseUrl: http://127.0.0.1:8080 queryPersonPageUrl: /gwzh/OA/OA_GET_USER_LIST + authorization: ${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:Z3d6aF90bXMtOVJJU0RVN1U6YW0yYkcwWnBJZ0RQZmtrSjNaZkZjUDBSaGFuSEtxQng=}} track: # 轨迹开放接口地址 baseUrl: http://127.0.0.1:8080 diff --git a/doc/nacos/third-party-api.yaml b/doc/nacos/third-party-api.yaml index a3fffa0..baa53a0 100644 --- a/doc/nacos/third-party-api.yaml +++ b/doc/nacos/third-party-api.yaml @@ -12,6 +12,7 @@ thirdParty: # OA开放接口地址 baseUrl: ${OA_BASE_URL:http://127.0.0.1:8080} queryPersonPageUrl: ${OA_QUERY_PERSON_PAGE_URL:/gwzh/OA/OA_GET_USER_LIST} + authorization: ${OA_AUTHORIZATION:${IAM_SSO_AUTHORIZATION:}} track: # 轨迹开放接口地址 baseUrl: ${TRACK_BASE_URL:http://127.0.0.1:8080}