From 339c793855717970540ba752ba999d06e17becac Mon Sep 17 00:00:00 2001 From: malei <> Date: Sun, 2 Aug 2026 02:45:22 +0800 Subject: [PATCH] fix: remove unfinished web oauth surface --- README.md | 1 - deploy/petstore-backend.env.example | 1 - deploy/release-preflight.sh | 7 +-- .../com/petstore/auth/AuthInterceptor.java | 4 -- .../ProductionConfigurationValidator.java | 19 ------- .../com/petstore/config/WechatConfig.java | 33 +++++-------- .../petstore/controller/WechatController.java | 49 ------------------- src/main/resources/application-example.yml | 1 - src/main/resources/application.yml | 1 - .../LegacyWechatOauthRemovalContractTest.java | 35 +++++++++++++ .../ProductionConfigurationValidatorTest.java | 1 - 11 files changed, 47 insertions(+), 105 deletions(-) delete mode 100644 src/main/java/com/petstore/controller/WechatController.java create mode 100644 src/test/java/com/petstore/config/LegacyWechatOauthRemovalContractTest.java diff --git a/README.md b/README.md index 4cd721d..e6bc4cd 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,6 @@ | `MYSQL_PASSWORD` | **是** | 空 | 数据库密码 | | `WECHAT_APPID` | 生产必填 | 空 | 微信小程序 AppID | | `WECHAT_APPSECRET` | 生产必填 | 空 | 微信小程序 AppSecret | -| `WECHAT_REDIRECT_URI` | 生产必填 | `http://localhost:8080/api/wechat/callback` | 微信回调;生产必须为真实 HTTPS 地址 | | `PETSTORE_SESSION_SECRET` | **生产必填** | `dev-change-me` | HMAC session token 签名密钥;改密会使所有已签发 token 立即失效 | | `PETSTORE_SESSION_TTL_SECONDS` | 否 | `604800`(7 天) | session token 有效期 | | `APP_BASE_URL` | 生产必填 | `http://localhost:8080` | 后端对外可访问 base URL(用于生成媒体绝对 URL) | diff --git a/deploy/petstore-backend.env.example b/deploy/petstore-backend.env.example index e3493a9..53fb6f2 100644 --- a/deploy/petstore-backend.env.example +++ b/deploy/petstore-backend.env.example @@ -9,7 +9,6 @@ MYSQL_PASSWORD= WECHAT_APPID= WECHAT_APPSECRET= -WECHAT_REDIRECT_URI=https://api.petstore.invalid/api/wechat/callback PETSTORE_SESSION_SECRET= SMS_UNIVERSAL_CODE= diff --git a/deploy/release-preflight.sh b/deploy/release-preflight.sh index 28e9ae8..31729f3 100755 --- a/deploy/release-preflight.sh +++ b/deploy/release-preflight.sh @@ -18,7 +18,7 @@ require_env() { } for name in MYSQL_URL MYSQL_USERNAME MYSQL_PASSWORD WECHAT_APPID WECHAT_APPSECRET \ - WECHAT_REDIRECT_URI PETSTORE_SESSION_SECRET APP_BASE_URL UPLOAD_PATH CORS_ALLOWED_ORIGINS; do + PETSTORE_SESSION_SECRET APP_BASE_URL UPLOAD_PATH CORS_ALLOWED_ORIGINS; do require_env "$name" done @@ -27,11 +27,6 @@ done [[ "$APP_BASE_URL" != *.invalid* ]] || fail "APP_BASE_URL must not use a placeholder domain" [[ "$APP_BASE_URL" != *.example* && "$APP_BASE_URL" != *.test* ]] \ || fail "APP_BASE_URL must not use a reserved example/test domain" -[[ "$WECHAT_REDIRECT_URI" == https://* ]] || fail "WECHAT_REDIRECT_URI must use https" -[[ "$WECHAT_REDIRECT_URI" != *localhost* && "$WECHAT_REDIRECT_URI" != *.invalid* ]] \ - || fail "WECHAT_REDIRECT_URI must use a production domain" -[[ "$WECHAT_REDIRECT_URI" != *.example* && "$WECHAT_REDIRECT_URI" != *.test* ]] \ - || fail "WECHAT_REDIRECT_URI must not use a reserved example/test domain" [[ ${#PETSTORE_SESSION_SECRET} -ge 32 ]] || fail "PETSTORE_SESSION_SECRET must be at least 32 characters" [[ "$PETSTORE_SESSION_SECRET" != "dev-change-me" ]] || fail "PETSTORE_SESSION_SECRET must not use the default" [[ -z "${SMS_UNIVERSAL_CODE:-}" ]] || fail "SMS_UNIVERSAL_CODE must be empty in production" diff --git a/src/main/java/com/petstore/auth/AuthInterceptor.java b/src/main/java/com/petstore/auth/AuthInterceptor.java index f9c2dc2..8e5d7e4 100644 --- a/src/main/java/com/petstore/auth/AuthInterceptor.java +++ b/src/main/java/com/petstore/auth/AuthInterceptor.java @@ -61,10 +61,6 @@ public class AuthInterceptor implements HandlerInterceptor { "POST /api/report/*/testimonial", "POST /api/report/unsubscribe", "POST /api/report/open-track", - // 微信网页授权 OAuth 回调链(与 wechat.redirect_uri 配置一致;callback 当前为 TODO demo, - // 真实微信登录走 /api/user/wx-phone-login,此处放行仅为兼容 redirect_uri 配置) - "GET /api/wechat/authorize", - "GET /api/wechat/callback", "GET /api/upload/image/**", "GET /api/upload/legacy/**", "GET /uploads/**" diff --git a/src/main/java/com/petstore/config/ProductionConfigurationValidator.java b/src/main/java/com/petstore/config/ProductionConfigurationValidator.java index ce941b4..a6e0880 100644 --- a/src/main/java/com/petstore/config/ProductionConfigurationValidator.java +++ b/src/main/java/com/petstore/config/ProductionConfigurationValidator.java @@ -20,7 +20,6 @@ public class ProductionConfigurationValidator { private final String mysqlPassword; private final String wechatAppId; private final String wechatAppSecret; - private final String wechatRedirectUri; private final String sessionSecret; private final String smsUniversalCode; private final String appBaseUrl; @@ -34,7 +33,6 @@ public class ProductionConfigurationValidator { @Value("${spring.datasource.password:}") String mysqlPassword, @Value("${wechat.appid:}") String wechatAppId, @Value("${wechat.appsecret:}") String wechatAppSecret, - @Value("${wechat.redirect_uri:}") String wechatRedirectUri, @Value("${auth.session-secret:}") String sessionSecret, @Value("${app.demo.sms-universal-code:}") String smsUniversalCode, @Value("${app.base-url:}") String appBaseUrl, @@ -46,7 +44,6 @@ public class ProductionConfigurationValidator { this.mysqlPassword = mysqlPassword; this.wechatAppId = wechatAppId; this.wechatAppSecret = wechatAppSecret; - this.wechatRedirectUri = wechatRedirectUri; this.sessionSecret = sessionSecret; this.smsUniversalCode = smsUniversalCode; this.appBaseUrl = appBaseUrl; @@ -70,7 +67,6 @@ public class ProductionConfigurationValidator { require(mysqlPassword, "MYSQL_PASSWORD", failures); require(wechatAppId, "WECHAT_APPID", failures); require(wechatAppSecret, "WECHAT_APPSECRET", failures); - requireHttpsUrl(wechatRedirectUri, "WECHAT_REDIRECT_URI", failures); if (text(sessionSecret).length() < 32 || "dev-change-me".equals(sessionSecret)) { failures.add("PETSTORE_SESSION_SECRET(至少32字符且非默认值)"); } @@ -97,13 +93,6 @@ public class ProductionConfigurationValidator { if (text(value).isEmpty()) failures.add(name); } - private static void requireHttpsUrl(String value, String name, List failures) { - String normalized = text(value); - if (!isSafeHttpsUrl(normalized)) { - failures.add(name + "必须为生产https地址"); - } - } - private static void requireHttpsOrigin(String value, String name, List failures) { if (!isSafeHttpsOrigin(text(value))) { failures.add(name + "必须为生产https源"); @@ -124,14 +113,6 @@ public class ProductionConfigurationValidator { } } - private static boolean isSafeHttpsUrl(String value) { - try { - return isSafeHttpsUri(URI.create(value)); - } catch (IllegalArgumentException ignored) { - return false; - } - } - private static boolean isSafeHttpsUri(URI uri) { String host = text(uri.getHost()).toLowerCase(); return "https".equalsIgnoreCase(uri.getScheme()) diff --git a/src/main/java/com/petstore/config/WechatConfig.java b/src/main/java/com/petstore/config/WechatConfig.java index 07c8d33..ee57407 100644 --- a/src/main/java/com/petstore/config/WechatConfig.java +++ b/src/main/java/com/petstore/config/WechatConfig.java @@ -3,31 +3,20 @@ package com.petstore.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; +/** 微信小程序服务端凭据;不承载已下线的网页 OAuth redirect 配置。 */ @Configuration public class WechatConfig { - // TODO: 替换为实际的微信开放平台 AppID 和 AppSecret - @Value("${wechat.appid:YOUR_APPID}") + @Value("${wechat.appid:}") private String appid; - - @Value("${wechat.appsecret:YOUR_APPSECRET}") + + @Value("${wechat.appsecret:}") private String appsecret; - - @Value("${wechat.redirect_uri:http://localhost:8080/api/wechat/callback}") - private String redirectUri; - - public String getAppid() { return appid; } - public String getAppsecret() { return appsecret; } - public String getRedirectUri() { return redirectUri; } - - /** - * 获取微信授权跳转地址 - */ - public String getAuthorizeUrl() { - return "https://open.weixin.qq.com/connect/qrconnect" + - "?appid=" + appid + - "&redirect_uri=" + redirectUri + - "&response_type=code" + - "&scope=snsapi_login" + - "&state=petstore#wechat_redirect"; + + public String getAppid() { + return appid; + } + + public String getAppsecret() { + return appsecret; } } diff --git a/src/main/java/com/petstore/controller/WechatController.java b/src/main/java/com/petstore/controller/WechatController.java deleted file mode 100644 index d492447..0000000 --- a/src/main/java/com/petstore/controller/WechatController.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.petstore.controller; - -import com.petstore.config.WechatConfig; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; - -import java.util.HashMap; -import java.util.Map; - -@RestController -@RequestMapping("/api/wechat") -@RequiredArgsConstructor -@CrossOrigin -public class WechatController { - private final WechatConfig wechatConfig; - - /** - * 获取微信授权跳转地址 - */ - @GetMapping("/authorize") - public Map getAuthorizeUrl() { - Map result = new HashMap<>(); - result.put("code", 200); - result.put("data", wechatConfig.getAuthorizeUrl()); - return result; - } - - /** - * 微信授权回调 - * 通过 code 换取 access_token,返回用户信息 - */ - @GetMapping("/callback") - public Map callback(@RequestParam String code, @RequestParam String state) { - Map result = new HashMap<>(); - - // TODO: 通过 code 调用微信接口换取 openid 和 access_token - // https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code - - // 演示用:直接返回成功 - result.put("code", 200); - result.put("message", "微信授权成功"); - result.put("data", Map.of( - "openid", "demo_openid_" + code, - "nickname", "微信用户", - "avatar", "" - )); - return result; - } -} diff --git a/src/main/resources/application-example.yml b/src/main/resources/application-example.yml index e33bd50..ad78e2f 100644 --- a/src/main/resources/application-example.yml +++ b/src/main/resources/application-example.yml @@ -43,7 +43,6 @@ logging: wechat: appid: ${WECHAT_APPID:} appsecret: ${WECHAT_APPSECRET:} - redirect_uri: ${WECHAT_REDIRECT_URI:http://localhost:8080/api/wechat/callback} # 服务回顾短片(ffmpeg;可选 ffprobe 读时长/音轨) app: diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index f18533c..3d332a2 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -71,7 +71,6 @@ app: wechat: appid: ${WECHAT_APPID:} appsecret: ${WECHAT_APPSECRET:} - redirect_uri: ${WECHAT_REDIRECT_URI:http://localhost:8080/api/wechat/callback} # 最小鉴权上下文:HMAC session token(不引入完整 Spring Security) # 生产必须通过环境变量覆盖 PETSTORE_SESSION_SECRET;勿提交真实密钥。 diff --git a/src/test/java/com/petstore/config/LegacyWechatOauthRemovalContractTest.java b/src/test/java/com/petstore/config/LegacyWechatOauthRemovalContractTest.java new file mode 100644 index 0000000..5078eee --- /dev/null +++ b/src/test/java/com/petstore/config/LegacyWechatOauthRemovalContractTest.java @@ -0,0 +1,35 @@ +package com.petstore.config; + +import org.junit.jupiter.api.Test; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +class LegacyWechatOauthRemovalContractTest { + + @Test + void unimplementedWebOauthSurfaceDoesNotReturnToThePilotRelease() throws Exception { + assertFalse(Files.exists(Path.of( + "src/main/java/com/petstore/controller/WechatController.java" + ))); + + for (Path path : List.of( + Path.of("src/main/java/com/petstore/auth/AuthInterceptor.java"), + Path.of("src/main/java/com/petstore/config/WechatConfig.java"), + Path.of("src/main/resources/application.yml"), + Path.of("src/main/resources/application-example.yml"), + Path.of("deploy/release-preflight.sh"), + Path.of("deploy/petstore-backend.env.example"), + Path.of("README.md") + )) { + String content = Files.readString(path); + assertFalse(content.contains("/api/wechat/authorize"), path.toString()); + assertFalse(content.contains("/api/wechat/callback"), path.toString()); + assertFalse(content.contains("WECHAT_REDIRECT_URI"), path.toString()); + assertFalse(content.contains("demo_openid_"), path.toString()); + } + } +} diff --git a/src/test/java/com/petstore/config/ProductionConfigurationValidatorTest.java b/src/test/java/com/petstore/config/ProductionConfigurationValidatorTest.java index e02e026..c8ac730 100644 --- a/src/test/java/com/petstore/config/ProductionConfigurationValidatorTest.java +++ b/src/test/java/com/petstore/config/ProductionConfigurationValidatorTest.java @@ -61,7 +61,6 @@ class ProductionConfigurationValidatorTest { "database-secret", "wx-app-id", "wx-app-secret", - "https://api.chongxiaota.cn/api/wechat/callback", "01234567890123456789012345678901", smsCode, "https://api.chongxiaota.cn",