diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e3390d9..53a8d42 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -182,6 +182,21 @@ gxmu: timeout-ms: 30000 max-retries: 2 page-size: 10000 + # 学校统一身份认证(微服务认证平台 API v2.3),小程序的「学号 + 统一身份认证密码」登录走这里。 + # + # appid/appsecret 由学校认证管理员在认证后台 - 应用管理 - 应用列表 中签发。 + # 2026-09-18 拿到后只在本地验证过(见 .scratch/student-sso/README.md 第 5.1 节), + # 但这段配置当时漏了提交,代码上线后 /api/sso/login 一直报 + # 「学校统一身份认证未配置,请联系管理员」——见本文件所在提交的说明。 + # 与 openplat 凭证同样处理:默认值写在这里,同时保留环境变量覆盖。 + auth: + enabled: true + base-url: https://cas.gxmu.edu.cn/lyuapServer + app-id: ${GXMU_AUTH_APPID:7D8F6695611309E0} + app-secret: ${GXMU_AUTH_APPSECRET:24f9dab5-3319-42cc-908d-2748417b7f92} + timeout-ms: 10000 + # 名册外的账号默认拒绝登录,见 ADR-0001:学生须先同步进名册 + allow-unknown-user: false openplat-sync: enabled: true # 每天 03:30 diff --git a/src/test/java/com/gxwebsoft/gxmu/auth/GxmuAuthPropertiesBindingTest.java b/src/test/java/com/gxwebsoft/gxmu/auth/GxmuAuthPropertiesBindingTest.java new file mode 100644 index 0000000..efea56a --- /dev/null +++ b/src/test/java/com/gxwebsoft/gxmu/auth/GxmuAuthPropertiesBindingTest.java @@ -0,0 +1,95 @@ +package com.gxwebsoft.gxmu.auth; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.env.YamlPropertySourceLoader; +import org.springframework.core.env.PropertySource; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.io.ClassPathResource; + +/** + * 校验 {@code gxmu.auth} 接入配置真的存在于 {@code application.yml} 并能绑定。 + * + *
背景(2026-09-21 生产现象): + * {@code /api/sso/login} 报「学校统一身份认证未配置,请联系管理员」, + * 而 {@code /api/sso/available} 返回 {@code false}。查下来 appid/appsecret + * 从来没有进过仓库 —— 代码、单测({@code SsoLoginServiceImplTest} 全程 mock + * {@code GxmuAuthProperties})、技术说明({@code .scratch/student-sso/README.md} 第 5.1 节 + * 写着「已写进 application.yml」)三者都齐了,唯独那份 yml 从未提交。 + * + *
后果是:单测全绿、功能全废。这与 Dify 那批配置当初踩的是同一类坑, + * 所以照 {@code DifyProdProfileBindingTest} 的做法加一道绑定断言 —— + * 光靠 mock 掉 {@code properties} 的单元测试永远发现不了「yml 里没这一段」。 + * + *
纯绑定测试,不启动 Spring 容器,不依赖数据库与 Redis,可直接跑。 + */ +class GxmuAuthPropertiesBindingTest { + + private GxmuAuthProperties load() throws Exception { + StandardEnvironment environment = new StandardEnvironment(); + for (PropertySource> source : new YamlPropertySourceLoader() + .load("application", new ClassPathResource("application.yml"))) { + environment.getPropertySources().addLast(source); + } + return Binder.get(environment).bind("gxmu.auth", GxmuAuthProperties.class).orElse(null); + } + + /** + * 这一段一旦缺失,登录接口会在 {@code available()} 处直接抛出, + * 且只有真实启动应用才看得见 —— 因此必须由测试钉住。 + */ + @Test + void applicationYml中存在gxmu_auth配置段() throws Exception { + GxmuAuthProperties properties = load(); + org.junit.jupiter.api.Assertions.assertNotNull(properties, + "application.yml 缺少 gxmu.auth 段:登录会报「学校统一身份认证未配置,请联系管理员」"); + } + + /** + * appid / appsecret 是登录可用的充要条件,任一为空 {@code available()} 即为 false, + * 小程序端会拿到 500 与「未配置」提示。 + */ + @Test + void appid与appsecret均已配置且非空() throws Exception { + GxmuAuthProperties properties = load(); + org.junit.jupiter.api.Assertions.assertNotNull(properties); + + org.junit.jupiter.api.Assertions.assertTrue(properties.isEnabled(), + "gxmu.auth.enabled 应默认为 true,否则登录入口直接关闭"); + org.junit.jupiter.api.Assertions.assertFalse( + cn.hutool.core.util.StrUtil.isBlank(properties.getAppId()), + "gxmu.auth.app-id 为空,请向学校认证管理员取得并写入 application.yml"); + org.junit.jupiter.api.Assertions.assertFalse( + cn.hutool.core.util.StrUtil.isBlank(properties.getAppSecret()), + "gxmu.auth.app-secret 为空,请向学校认证管理员取得并写入 application.yml"); + } + + /** + * 认证平台地址由校方提供,绑错会表现为"无法连接"而非"未配置",同样难查。 + */ + @Test + void 认证平台地址指向学校lyuapServer() throws Exception { + GxmuAuthProperties properties = load(); + org.junit.jupiter.api.Assertions.assertNotNull(properties); + + org.junit.jupiter.api.Assertions.assertEquals("https://cas.gxmu.edu.cn/lyuapServer", + properties.getBaseUrl()); + } + + /** + * 端到端语义:yml 里配了,{@code available()} 就必须为 true。 + * 这条是本测试存在的理由 —— 前三条只证明"配置在",这条证明"配置够用"。 + */ + @Test + void 配置齐备时available返回true() throws Exception { + GxmuAuthProperties properties = load(); + org.junit.jupiter.api.Assertions.assertNotNull(properties); + + SsoLoginServiceImpl service = new SsoLoginServiceImpl(); + org.springframework.test.util.ReflectionTestUtils.setField(service, "properties", properties); + + org.junit.jupiter.api.Assertions.assertTrue(service.available(), + "yml 里配置齐备时 available() 必须为 true,否则小程序端会认为该登录方式不可用"); + } + +}