fix: 改用 nacos_config.py 运行时注入 Nacos 配置(替代失效的 EPP);CI 改为 maven 从源码构建 war,移除提交的 168MB cas.war
deploy-cassso-service / build-deploy (push) Successful in 13m33s
deploy-cassso-service / build-deploy (push) Successful in 13m33s
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# 缩小 docker build 上下文(Dockerfile 只需 target/cas.war、docker/*、etc/cas/config/log4j2.xml)
|
||||
src
|
||||
.gitea
|
||||
.git
|
||||
*.md
|
||||
maven-settings.xml
|
||||
docker/cas.war
|
||||
docker/cas.war.bak
|
||||
@@ -8,7 +8,8 @@ on:
|
||||
jobs:
|
||||
build-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
# docker:24 自带 docker CLI;宿主 docker.sock 默认挂入 job 容器。
|
||||
# docker:24 自带 docker CLI;宿主 docker.sock 默认挂入 job 容器,
|
||||
# 因此 docker build/run 实际都在宿主守护进程上执行。
|
||||
container:
|
||||
image: docker:24
|
||||
steps:
|
||||
@@ -16,22 +17,35 @@ jobs:
|
||||
run: apk add --no-cache git
|
||||
|
||||
- name: Checkout (manual, internal Gitea)
|
||||
# cas.war (174MB) 已作为普通 blob 入库(服务端未启用 LFS)
|
||||
run: |
|
||||
git clone --depth 1 --branch main http://192.168.10.160:3000/${GITHUB_REPOSITORY}.git /tmp/src
|
||||
cp -a /tmp/src/. .
|
||||
rm -rf .git .gitea
|
||||
rm -rf /tmp/src
|
||||
|
||||
- name: Build image (copies docker/cas.war) on host daemon
|
||||
# 经由挂载的 docker.sock 在宿主守护进程上构建,镜像直接落在宿主本地
|
||||
# 用宿主 docker 守护进程跑 maven 3.9(--network=host 走宿主网络拉 nexus 依赖)。
|
||||
# 重要:job 容器内 $PWD 不是宿主可见路径,不能直接 `-v $PWD:/build` 挂给 maven 容器
|
||||
# (docker.sock 跨边界 bind mount 会落到宿主空目录,maven 看不到 pom.xml)。
|
||||
# 改用 docker create + docker cp 把源码送进 maven 容器,构建完再把 target 拷回工作区。
|
||||
# war 由 maven 从源码构建(target/cas.war),不再把 war 提交进 git。
|
||||
- name: Build war (maven 3.9, nexus maven-public)
|
||||
run: |
|
||||
MVN=$(docker create --network=host -v /opt/docker/ubs-m2:/root/.m2 -w /build maven:3.9-eclipse-temurin-8 mvn -s maven-settings.xml -B -DskipTests package)
|
||||
docker cp "$PWD/." "$MVN:/build"
|
||||
docker start -a "$MVN"
|
||||
docker cp "$MVN:/build/target" "$PWD/target"
|
||||
docker rm -f "$MVN"
|
||||
|
||||
- name: Build image on host daemon
|
||||
# 构建上下文=仓库根目录,Dockerfile 内 COPY target/cas.war;
|
||||
# 业务配置由 run-cas.sh 在启动时调用 nacos_config.py 从 Nacos 拉取(替代失效的 EPP)。
|
||||
run: docker build -f docker/Dockerfile -t cassso-service:latest .
|
||||
|
||||
- name: Deploy on host (infra-infra-net, CAS 端口 8443)
|
||||
# 镜像已在宿主本地,直接运行,无需推送到 nexus(nexus docker 仓库为 HTTP,需 daemon insecure-registries 才能推送)
|
||||
# Nacos 环境变量:NacosEnvironmentPostProcessor 启动阶段据此从 Nacos 原生拉取
|
||||
# common.yaml (DEFAULT_GROUP) + cas.yaml (CAS group),namespace=prod。
|
||||
# Nacos 环境变量:run-cas.sh 据此在启动阶段从 Nacos 拉取业务配置(common.yaml + cas.yaml, prod)。
|
||||
# 不传 NACOS_NAMESPACE 会默认连 dev(dev 命名空间无配置),登录必失败——必须显式传 prod。
|
||||
# 注意:镜像构建成功才会走到本步;若上面 maven/docker build 失败,本步不执行,旧容器继续运行。
|
||||
run: |
|
||||
docker rm -f cas-sso 2>/dev/null || true
|
||||
docker run -d --name cas-sso --network infra-infra-net -p 8443:8443 --restart unless-stopped \
|
||||
@@ -42,4 +56,4 @@ jobs:
|
||||
cassso-service:latest
|
||||
|
||||
- name: Done
|
||||
run: 'echo "CasSsoService deployed -> https://192.168.10.160:8443/login"'
|
||||
run: 'echo "CasSsoService deployed -> http://sso.yunhaixingtong.com/cas"'
|
||||
|
||||
@@ -16,3 +16,10 @@ docker/diag2_out.txt
|
||||
# 前端由 CasSsoFront 仓库独立发布,本后端仓库只发纯后端(cas.war)
|
||||
src/main/webapp/front/
|
||||
*.iml
|
||||
# 构建产物与二进制不入库(CI 用 maven 从源码构建 cas.war)
|
||||
target/
|
||||
*.war
|
||||
docker/*.war
|
||||
docker/cas.war.bak
|
||||
nacos-config-injector.jar
|
||||
_injector_build/
|
||||
|
||||
+9
-6
@@ -1,4 +1,4 @@
|
||||
# CAS 5.3.16 镜像(基于已构建好的 target/cas.war)
|
||||
# CAS 5.3.16 镜像(cas.war 由 CI 用 maven 从源码构建,落在 target/cas.war)
|
||||
# 构建上下文 = 项目根目录: docker build -f docker/Dockerfile -t <img> .
|
||||
FROM eclipse-temurin:8-jre
|
||||
|
||||
@@ -7,18 +7,21 @@ RUN mkdir -p /etc/cas/config \
|
||||
&& keytool -genkeypair -alias cas -keyalg RSA -keysize 2048 -validity 3650 \
|
||||
-storetype JKS -keystore /etc/cas/cas.keystore \
|
||||
-storepass changeit -keypass changeit -dname "CN=cas.example.org" 2>/dev/null || true \
|
||||
&& apt-get update && apt-get install -y --no-install-recommends curl \
|
||||
&& apt-get update && apt-get install -y --no-install-recommends curl python3 python3-yaml \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
COPY docker/cas.war /app/cas.war
|
||||
# cas.war 由 maven 源码构建产出(target/cas.war),不再把 war 提交进 git
|
||||
COPY target/cas.war /app/cas.war
|
||||
COPY docker/cas.properties /etc/cas/config/cas.properties
|
||||
COPY docker/nacos_config.py /app/nacos_config.py
|
||||
COPY docker/run-cas.sh /app/run-cas.sh
|
||||
COPY etc/cas/config/log4j2.xml /etc/cas/config/log4j2.xml
|
||||
RUN chmod +x /app/run-cas.sh
|
||||
|
||||
# 镜像内 cas.properties 仅保留本地无关配置(HTTPS/端口/日志/管理页白名单);
|
||||
# 业务配置(cas.server.name / JDBC / Redis 等)由 NacosEnvironmentPostProcessor 在启动阶段
|
||||
# 从 Nacos 原生拉取(common.yaml + cas.yaml,namespace=NACOS_NAMESPACE),镜像保持环境无关。
|
||||
# 业务配置(cas.server.name / JDBC / Redis / always-captcha 等)由 run-cas.sh 在启动阶段
|
||||
# 调用 nacos_config.py 从 Nacos 原生拉取(common.yaml + cas.yaml,namespace=NACOS_NAMESPACE),
|
||||
# 生成 /etc/cas/config/cas.properties(CAS 5.3 原生加载,优先级高于 classpath application.yml)。
|
||||
# 替代失效的 EnvironmentPostProcessor(CAS 5.3 + Spring Cloud bootstrap 下 EPP 不触发)。
|
||||
EXPOSE 8443
|
||||
ENTRYPOINT ["/app/run-cas.sh"]
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env python3
|
||||
# 启动前从 Nacos 拉取 common.yaml + cas.yaml,生成 /etc/cas/config/cas.properties。
|
||||
# 替代失效的 EnvironmentPostProcessor(CAS 5.3 + Spring Cloud bootstrap 下 EPP 不触发)。
|
||||
# CAS 5.3 原生加载 /etc/cas/config/cas.properties(profile=standalone),优先级高于 classpath application.yml。
|
||||
import os, sys, json, urllib.request, urllib.parse, yaml
|
||||
|
||||
ADDR = os.environ.get("NACOS_ADDR", "nacos.yunhaixingtong.com:8848")
|
||||
NS = os.environ.get("NACOS_NAMESPACE", "dev")
|
||||
USER = os.environ.get("NACOS_USER", "yh-reader")
|
||||
PASS = os.environ.get("NACOS_PASS", "123456")
|
||||
OUT = os.environ.get("CAS_PROPERTIES", "/etc/cas/config/cas.properties")
|
||||
|
||||
# 库名默认值(cas.yaml 的 cas.authn.jdbc.query[0].database 仅用于拼 jdbc url,不作为独立属性写入)
|
||||
DEFAULT_DB = "bsch_userbase"
|
||||
DEFAULT_PARAMS = "useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"
|
||||
|
||||
# CAS 不识别的属性(写入会导致 RelaxedBinding 崩溃),从输出中排除
|
||||
EXCLUDE_KEYS = {"cas.authn.jdbc.query[0].database", "cas.authn.jdbc.query[0].dialect"}
|
||||
|
||||
# 本地兜底配置(与运行环境无关,烤进 cas.properties)
|
||||
LOCAL_CONFIG = """server.port: 8443
|
||||
server.ssl.enabled: true
|
||||
server.ssl.key-store: /etc/cas/cas.keystore
|
||||
server.ssl.key-store-password: changeit
|
||||
server.ssl.key-password: changeit
|
||||
server.ssl.key-alias: cas
|
||||
logging.config: file:/etc/cas/config/log4j2.xml
|
||||
cas.adminPagesSecurity.ip=127\\.0\\.0\\.1
|
||||
"""
|
||||
|
||||
|
||||
def http_get(url, timeout=10):
|
||||
try:
|
||||
with urllib.request.urlopen(url, timeout=timeout) as r:
|
||||
return r.read().decode("utf-8") if r.status == 200 else None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def http_post(url, data=b"", timeout=10):
|
||||
try:
|
||||
req = urllib.request.Request(url, data=data, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=timeout) as r:
|
||||
return r.read().decode("utf-8") if r.status == 200 else None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def login():
|
||||
url = "http://%s/nacos/v1/auth/login?username=%s&password=%s" % (
|
||||
ADDR, urllib.parse.quote(USER), urllib.parse.quote(PASS))
|
||||
resp = http_post(url)
|
||||
if not resp:
|
||||
return None
|
||||
try:
|
||||
return json.loads(resp).get("accessToken")
|
||||
except Exception:
|
||||
i = resp.find('"accessToken"')
|
||||
if i < 0:
|
||||
return None
|
||||
s = resp.find('"', i + 14)
|
||||
e = resp.find('"', s + 1)
|
||||
return resp[s + 1:e] if s >= 0 and e > s else None
|
||||
|
||||
|
||||
def resolve_ns(token):
|
||||
if not NS:
|
||||
return ""
|
||||
url = "http://%s/nacos/v1/console/namespaces" % ADDR
|
||||
if token:
|
||||
url += "?accessToken=" + urllib.parse.quote(token)
|
||||
body = http_get(url)
|
||||
if not body:
|
||||
return NS
|
||||
try:
|
||||
data = json.loads(body).get("data", [])
|
||||
except Exception:
|
||||
return NS
|
||||
for item in data:
|
||||
if NS == item.get("namespaceShowName") or NS == item.get("namespace"):
|
||||
return item.get("namespace", "")
|
||||
return NS
|
||||
|
||||
|
||||
def fetch_yaml(data_id, group, nsid, token):
|
||||
base = "http://%s/nacos/v1/cs/configs" % ADDR
|
||||
qs = "dataId=%s&group=%s&tenant=%s" % (
|
||||
urllib.parse.quote(data_id), urllib.parse.quote(group), urllib.parse.quote(nsid))
|
||||
if token:
|
||||
content = http_get("%s?%s&accessToken=%s" % (base, qs, urllib.parse.quote(token)))
|
||||
if content and content.strip() and '"error"' not in content:
|
||||
return content
|
||||
return http_get("%s?%s" % (base, qs)) or ""
|
||||
|
||||
|
||||
def flatten(prefix, value, out):
|
||||
if isinstance(value, dict):
|
||||
for k, v in value.items():
|
||||
flatten(k if not prefix else prefix + "." + k, v, out)
|
||||
elif isinstance(value, list):
|
||||
for i, v in enumerate(value):
|
||||
flatten("%s[%d]" % (prefix, i) if prefix else "[%d]" % i, v, out)
|
||||
elif value is not None:
|
||||
out[prefix] = value
|
||||
|
||||
|
||||
def parse_yaml(content):
|
||||
if not content or not content.strip():
|
||||
return {}
|
||||
data = yaml.safe_load(content) or {}
|
||||
flat = {}
|
||||
flatten("", data, flat)
|
||||
return flat
|
||||
|
||||
|
||||
def esc(v):
|
||||
if isinstance(v, bool):
|
||||
return "true" if v else "false"
|
||||
s = str(v)
|
||||
s = s.replace("\\", "\\\\")
|
||||
return s
|
||||
|
||||
|
||||
def build(common, cas):
|
||||
merged = {}
|
||||
# cas.yaml 透传(排除无效属性)
|
||||
for k, v in cas.items():
|
||||
if k not in EXCLUDE_KEYS:
|
||||
merged[k] = v
|
||||
# datasource -> jdbc url(与 EPP buildCasProperties 逻辑一致)
|
||||
ds_host = common.get("spring.datasource.host") or common.get("mysql.host")
|
||||
ds_port = common.get("spring.datasource.port") or common.get("mysql.port") or 3306
|
||||
ds_user = common.get("spring.datasource.username") or common.get("mysql.user")
|
||||
ds_pass = common.get("spring.datasource.password") or common.get("mysql.password")
|
||||
ds_params = common.get("spring.datasource.params") or common.get("mysql.params") or DEFAULT_PARAMS
|
||||
db_name = cas.get("cas.authn.jdbc.query[0].database", DEFAULT_DB)
|
||||
if ds_host:
|
||||
jdbc_url = "jdbc:mysql://%s:%s/%s?%s" % (ds_host, ds_port, db_name, ds_params)
|
||||
merged["cas.authn.jdbc.query[0].url"] = jdbc_url
|
||||
if ds_user:
|
||||
merged["cas.authn.jdbc.query[0].user"] = ds_user
|
||||
if ds_pass:
|
||||
merged["cas.authn.jdbc.query[0].password"] = ds_pass
|
||||
merged["cas.authn.jdbc.query[0].driverClass"] = "com.mysql.jdbc.Driver"
|
||||
# 透传 redis / rabbitmq
|
||||
for k, v in common.items():
|
||||
if k.startswith("spring.redis.") or k.startswith("spring.rabbitmq."):
|
||||
merged[k] = v
|
||||
return merged
|
||||
|
||||
|
||||
def main():
|
||||
token = login()
|
||||
nsid = resolve_ns(token)
|
||||
common_raw = fetch_yaml("common.yaml", "DEFAULT_GROUP", nsid, token)
|
||||
cas_raw = fetch_yaml("cas.yaml", "CAS", nsid, token)
|
||||
common = parse_yaml(common_raw)
|
||||
cas = parse_yaml(cas_raw)
|
||||
if not common and not cas:
|
||||
print("[nacos_config] WARN: 未拉到任何 Nacos 配置,保留现有 cas.properties", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
merged = build(common, cas)
|
||||
|
||||
lines = [
|
||||
"# 由 nacos_config.py 从 Nacos 生成(勿手改)",
|
||||
"# namespace=%s nsid=%s common_keys=%d cas_keys=%d" % (NS, nsid, len(common), len(cas)),
|
||||
]
|
||||
for k in sorted(merged.keys()):
|
||||
lines.append("%s=%s" % (k, esc(merged[k])))
|
||||
lines.append("")
|
||||
lines.append("# === 本地兜底配置 ===")
|
||||
lines.append(LOCAL_CONFIG.rstrip("\n"))
|
||||
|
||||
content = "\n".join(lines) + "\n"
|
||||
os.makedirs(os.path.dirname(OUT), exist_ok=True)
|
||||
with open(OUT, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
print("[nacos_config] wrote %d props -> %s" % (len(merged), OUT))
|
||||
print("[nacos_config] always-captcha=%s redis.host=%s jdbc.host=%s server.name=%s" % (
|
||||
merged.get("custom.login.always-captcha"),
|
||||
merged.get("spring.redis.host"),
|
||||
common.get("spring.datasource.host"),
|
||||
merged.get("cas.server.name")))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+7
-7
@@ -1,12 +1,12 @@
|
||||
#!/bin/sh
|
||||
# CAS 启动入口(原生 Nacos 配置注入版)
|
||||
# 业务配置改由 org.apereo.cas.web.custom.config.nacos.NacosEnvironmentPostProcessor
|
||||
# 在 Spring Boot 环境准备阶段从 Nacos 原生拉取:
|
||||
# - 公共基础配置 common.yaml (namespace=NACOS_NAMESPACE, group=DEFAULT_GROUP)
|
||||
# - CAS 自身配置 cas.yaml (namespace=NACOS_NAMESPACE, group=CAS)
|
||||
# 不再需要本脚本写 /etc/cas/config/cas.properties,CAS 镜像保持环境无关。
|
||||
# CAS 启动入口
|
||||
# 配置注入:启动前用 python3 从 Nacos 拉 common.yaml+cas.yaml 生成 /etc/cas/config/cas.properties。
|
||||
# 替代失效的 EnvironmentPostProcessor(CAS 5.3 + Spring Cloud bootstrap 下 EPP 不触发)。
|
||||
# CAS 5.3 原生加载 /etc/cas/config/cas.properties(profile=standalone),优先级高于 classpath application.yml。
|
||||
set -e
|
||||
|
||||
echo "[run-cas] Nacos 原生配置注入:NACOS_ADDR=${NACOS_ADDR:-<unset>} NACOS_NAMESPACE=${NACOS_NAMESPACE:-<unset>} NACOS_USER=${NACOS_USER:-<unset>}"
|
||||
echo "[run-cas] Nacos 配置注入:NACOS_ADDR=${NACOS_ADDR:-<unset>} NACOS_NAMESPACE=${NACOS_NAMESPACE:-<unset>} NACOS_USER=${NACOS_USER:-<unset>}"
|
||||
|
||||
python3 /app/nacos_config.py || echo "[run-cas] WARN: nacos_config.py 失败,用镜像内 cas.properties 兜底"
|
||||
|
||||
exec java -jar /app/cas.war
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<settings>
|
||||
<!-- Maven 3.8+ 默认拦截 HTTP 仓库(maven-default-http-blocker)。
|
||||
nexus maven-public 仅提供 HTTP,故在此覆盖该 blocker,放行内网 nexus。 -->
|
||||
<mirrors>
|
||||
<mirror>
|
||||
<id>maven-default-http-blocker</id>
|
||||
<mirrorOf>external:http:*</mirrorOf>
|
||||
<name>nexus maven-public (allow http)</name>
|
||||
<url>http://192.168.10.160:8081/repository/maven-public/</url>
|
||||
<blocked>false</blocked>
|
||||
</mirror>
|
||||
</mirrors>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>nexus</id>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<url>http://192.168.10.160:8081/repository/maven-public/</url>
|
||||
<releases><enabled>true</enabled></releases>
|
||||
<snapshots><enabled>true</enabled></snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>central</id>
|
||||
<url>http://192.168.10.160:8081/repository/maven-public/</url>
|
||||
<releases><enabled>true</enabled></releases>
|
||||
<snapshots><enabled>true</enabled></snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</profile>
|
||||
</profiles>
|
||||
<activeProfiles>
|
||||
<activeProfile>nexus</activeProfile>
|
||||
</activeProfiles>
|
||||
</settings>
|
||||
@@ -360,6 +360,14 @@
|
||||
<version>4.2.10.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- SnakeYAML:解析 Nacos 下发的 YAML 配置(webapp 已自带 1.17,provided 仅用于编译期,运行期复用 webapp 版本避免冲突) -->
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.17</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
+19
@@ -83,17 +83,33 @@ public class NacosEnvironmentPostProcessor implements EnvironmentPostProcessor,
|
||||
String casDataId = firstNonNull(environment.getProperty("nacos.config.cas-data-id"), "cas.yaml");
|
||||
String casGroup = firstNonNull(environment.getProperty("nacos.config.cas-group"), "CAS");
|
||||
|
||||
System.out.println("[EPP-DEBUG] ===== postProcessEnvironment START =====");
|
||||
System.out.println("[EPP-DEBUG] NACOS_ADDR=" + addr + " NACOS_NAMESPACE=" + namespace
|
||||
+ " NACOS_USER=" + username + " commonDataId=" + commonDataId + "/" + commonGroup
|
||||
+ " casDataId=" + casDataId + "/" + casGroup);
|
||||
try {
|
||||
String token = login(addr, username, password);
|
||||
System.out.println("[EPP-DEBUG] login token=" + (token == null ? "null" : token.substring(0, Math.min(20, token.length())) + "..."));
|
||||
// 把命名空间名字(dev/prod)解析成 Nacos 的 namespaceId:
|
||||
// 配置接口 tenant 参数只认 ID 不认名字,直接传 "prod" 会查不到配置。
|
||||
String resolvedNs = resolveNamespace(addr, namespace, token);
|
||||
System.out.println("[EPP-DEBUG] resolvedNs=" + resolvedNs);
|
||||
|
||||
Map<String, Object> common = fetchYaml(addr, commonDataId, commonGroup, resolvedNs, token);
|
||||
Map<String, Object> cas = fetchYaml(addr, casDataId, casGroup, resolvedNs, token);
|
||||
System.out.println("[EPP-DEBUG] common keys=" + (common == null ? 0 : common.size())
|
||||
+ " cas keys=" + (cas == null ? 0 : cas.size()));
|
||||
if (cas != null) {
|
||||
System.out.println("[EPP-DEBUG] cas always-captcha=" + cas.get("custom.login.always-captcha")
|
||||
+ " server.name=" + cas.get("cas.server.name"));
|
||||
}
|
||||
|
||||
Map<String, Object> merged = buildCasProperties(common, cas);
|
||||
System.out.println("[EPP-DEBUG] merged size=" + merged.size()
|
||||
+ " always-captcha=" + merged.get("custom.login.always-captcha")
|
||||
+ " redis.host=" + merged.get("spring.redis.host"));
|
||||
if (merged.isEmpty()) {
|
||||
System.out.println("[EPP-DEBUG] merged EMPTY, fallback application.yml");
|
||||
log.warn("[nacos] 未从 Nacos 解析出任何有效配置,回退 application.yml");
|
||||
return;
|
||||
}
|
||||
@@ -107,8 +123,11 @@ public class NacosEnvironmentPostProcessor implements EnvironmentPostProcessor,
|
||||
} else {
|
||||
sources.addFirst(source);
|
||||
}
|
||||
System.out.println("[EPP-DEBUG] INJECTED OK before=" + appName + " size=" + merged.size());
|
||||
log.info("[nacos] 已从 Nacos 注入 {} 个配置项 (namespace='{}' -> '{}', addr={})", merged.size(), namespace, resolvedNs, addr);
|
||||
} catch (Exception e) {
|
||||
System.out.println("[EPP-DEBUG] FAILED: " + e);
|
||||
e.printStackTrace();
|
||||
log.warn("[nacos] 加载 Nacos 配置失败,回退 application.yml:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,21 +114,21 @@ public class LoginController {
|
||||
@RequestParam("pwd") String encryptedPassword,
|
||||
@RequestParam(value = "captcha", required = false) String captchaText,
|
||||
@RequestParam(value = "service", required = false) String service,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
|
||||
// 前端未对 service 做 URL 解码(bschlogin.js getQueryVariable 直接 slice 不做 decodeURIComponent),
|
||||
// 会把浏览器地址栏里百分号编码态的 service(http%3A%2F%2F...)原样 POST 给后端,导致
|
||||
// WebApplicationServiceFactory.createService 拿到的仍是编码串,CAS 服务注册表正则
|
||||
// ^(https|imaps|http)://.* 匹配不到而抛 UnauthorizedServiceException(带 service 登录报“建立会话失败”)。
|
||||
// 统一在此把 service 解码成真实 URL(http://...)并向后透传解码值,方便后续其它逻辑直接读取。
|
||||
if (service != null && !service.trim().isEmpty()) {
|
||||
try {
|
||||
service = URLDecoder.decode(service, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
logger.warn("service 参数 URL 解码失败,按原值使用: {}", service);
|
||||
}
|
||||
// 前端未对 service 做 URL 解码(bschlogin.js getQueryVariable 直接 slice 不做 decodeURIComponent),
|
||||
// 会把浏览器地址栏里百分号编码态的 service(http%3A%2F%2F...)原样 POST 给后端,导致
|
||||
// WebApplicationServiceFactory.createService 拿到的仍是编码串,CAS 服务注册表正则
|
||||
// ^(https|imaps|http)://.* 匹配不到而抛 UnauthorizedServiceException(带 service 登录报“建立会话失败”)。
|
||||
// 统一在此把 service 解码成真实 URL(http://...)并向后透传解码值,方便后续其它逻辑直接读取。
|
||||
if (service != null && !service.trim().isEmpty()) {
|
||||
try {
|
||||
service = URLDecoder.decode(service, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
logger.warn("service 参数 URL 解码失败,按原值使用: {}", service);
|
||||
}
|
||||
}
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user