# Option B variant: Weaver E10 OAuth via qy.war (BaoYPro) Session model stays **Option B** (`index2sso.jsp` + `LtpaTokenManager`). OAuth lives in custom **qy.war** (`/qy/auth/...`) under Kingdee `lib/sp` + `easweb.ear/qy.war`. Primary reference project: **BaoYPro** (报业 / 泛微 E10). Prefer **explicit** `/qy/auth/weaver/...` over Unified `/qy/auth/app` (UA detection). **New project:** complete **Agent intake** in [SKILL.md](SKILL.md) before coding. --- ## When to use | Scenario | Fit | |----------|-----| | 泛微 E10 OAuth2 门户 / 待办进 sHR | Yes | | 钉钉 OAuth 进 sHR(显式 `/auth/dingtalk`) | Yes — same POST index2sso landing | | IdP redirect_uri must stay without `.do` | Yes (Filter forwards internally) | | Rely on Unified `/auth/app` + User-Agent | No for PC deep links / Weaver todos | | All `/shr` URLs auto OAuth without click entry | No — use Option A | | OTP / WeChart OTP auto login | No — use `OTP2sso.jsp`, not this | --- ## BaoYPro end-to-end (current) ``` Portal eassso/login?service=SHR_URL → sso_web login_withForm.js (keep /shr/home.do native) → /qy/auth/weaver/app.do?appId=&redirect= → state=Base64Url(redirect|appType) → 泛微 authorize → callback /qy/auth/callback/weaver/pa?code&state → CallbackSuffixCompatFilter → forward pa.do → code → accessToken → profile → map sHR user (PERSON_NUMBER) → WeaverShrLanding.writePostForm → HTML POST /shr/index2sso.jsp → SHR session → redirectTo ``` Todo / logout deep links use the **same** `/qy/auth/weaver/app.do` entry (not Unified `/auth/app`). ### Config | Source | Role | |--------|------| | `INTEGRATION_CONFIG_PATH` → `integration-config-*.json` | `common.*`, `oauth.apps[]`, `weaver.ecologyUrl` + OAuth paths | | `weaver.ecologyUrl` | authorize / accessToken / profile / **logout** (IdP) | | `oauth.apps[].callbackUrl` | IdP redirect_uri (**no** `.do`) | | `oauth.apps[].appId` / `appSecret` | E10 client_id / secret | | `desktopRedirectType=TO_SHR` | PC → index2sso POST | Do **not** put Weaver OpenAPI push secrets in this JSON — those stay in `weaverTodoConfig.properties` (kdshrpmsg). Register with 泛微: **exact** `callbackUrl` string (protocol/host/port/path). --- ## UnifiedAuth `/auth/app` vs WeaverAuthController | | `UnifiedAuthController` `/auth/app` | `WeaverAuthController` `/auth/weaver/app` | |--|--|--| | Platform select | **User-Agent** detectors | Explicit weaver + `appId` | | PC browser from Weaver todo | Often `unsupported_client` | Works | | Landing | Base `doCallback` often **302 Location + LTPA** | **POST** form (`WeaverShrLanding`) | | Minimize base edits | Needs UA / landing hooks in base | Keep changes in weaver package | **Rule:** PC 深链 / 待办 / 门户桥 → `/qy/auth/weaver/app(.do)`. App WebView + reliable UA → Unified `/auth/app` OK for DingTalk-in-app. Future DingTalk todo/SSO: add `/qy/auth/dingtalk/...` (explicit), reuse POST index2sso; do not force everything through UA-based `/auth/app`. --- ## Two hard Apusic problems (must fix both) ### 1) Callback 404 without `.do` | Piece | Role | |-------|------| | `CallbackSuffixCompatFilter` on `/auth/callback/*` | forward to `.do`, query preserved | | Controller | Map both `/callback/.../pa` and `/pa.do` | | `suffix-pattern="false"` | `pa` is path var | | `web.xml` | `*.do` and `/` | ### 2) Copy-paste required to login (`%2525252B`) LTPA in **302 Location** → Apusic multi-encode. **Fix:** HTML form **POST** to `/shr/index2sso.jsp` (`WeaverShrLanding.writePostForm` / base `writeShrSsoLoginForm`). Never put LTPA password in Location. --- ## Apusic AttackFilter (Referer / “跨域” 404) Not classic CORS. Global filter: `{EAS_HOME}/apusic/domains/server1/config/web.xml` → `com.apusic.util.AttackFilter` | Param | Role | |-------|------| | `enableCSRFCheck` | Master switch for Referer check | | `enableCSRFCheck_URL` | Allow URI via `allow_URLS` when CSRF on | | `serverNameWhiteList` | Referer host allow list | | `allow_URLS` | Path prefixes (include `/qy/` if CSRF on) | `shr_web` `enableSHRRequestParamWrapFilter` is **not** cross-origin control (param wrap on `/shr` only). Symptom: external Referer (Weaver) → `/qy/...` 404/403; no Referer / same-host → OK. Prefer whitelist `/qy/` + Weaver host over disabling CSRF globally. --- ## Federated logout (BaoYPro) ### Desired UX 1. Clear SHR/EAS local sessions (`logoutHR.js` product chain) 2. Redirect to `/qy/auth/weaver/logout.do?appId=&redirect=` 3. Server sets Weaver logout `service` = **SHR SSO entry** `http://{shr}/qy/auth/weaver/app.do?appId=&redirect=` 4. Browser `encodeURIComponent(service)` then jump to `{ecology}/sp/integration/oauth2.0/logout?service=...` 5. User sees Weaver login; after password → SSO entry → OAuth → SHR ### Critical ops Weaver docs: **`service` domain must be on 退出重定向白名单**. Otherwise Weaver rewrites to ecology home (`service=http://ecology/`), login stays in Weaver (e.g. workflow center). Whitelist at least: `http://{shrHost}:{port}` (e.g. `http://172.16.38.1:6888`). ### Code pieces | Piece | Role | |-------|------| | `logoutHR.js` 二开块 | After local logout → `/qy/auth/weaver/logout.do?appId&redirect` | | `WeaverAuthController.logout` | Build SSO entry as `service` | | `WeaverShrLanding.writeLogoutThenService` | HTML + JS encode (avoid double-encode) | Do **not** set `service` to ecology homepage. Do **not** expect external `service` to work without whitelist. --- ## Portal JS (login_withForm.js) ``` oaSsoUrl = http://{host}/qy/auth/weaver/app.do + appId= + redirect=service/target ``` Whitelist: `/shr/home.do` native. Prefer src overlay for sso_web. --- ## Deploy checklist ``` - [ ] integration jar → {EAS_HOME}/server/lib/sp/ - [ ] qy.war in easweb.ear application.xml + deployed - [ ] INTEGRATION_CONFIG_PATH; callbackUrl == 泛微注册 - [ ] login_withForm.js → /qy/auth/weaver/app.do - [ ] logoutHR.js 二开 + 泛微 service 白名单 - [ ] AttackFilter: /qy/ allowed or CSRF off only if accepted - [ ] ssoParamemter UrlPattern includes /index2sso.jsp - [ ] Restart; private window for OAuth code ``` --- ## Troubleshooting | Symptom | Check | |---------|--------| | Callback 404 `/callback/weaver/pa` | Filter + `.do` mapping + suffix-pattern | | `%2525252B` / must paste URL | Still GET Location — deploy POST form landing | | External Referer → `/qy` 404 | AttackFilter CSRF / whitelist `/qy/` | | Logout then stay in Weaver | `service` not whitelisted; address bar still `service=ecology/` | | Logout login page `service=ecology/` | White list OR old JS/jar not deployed | | `unsupported_client` on `/auth/app` | UA miss — use `/auth/weaver/app` | | 80013 redirect_uri | callbackUrl vs IdP register mismatch | | qy 404 always | qy.war missing from live `easweb.ear` | --- ## Key classes / paths (BaoYPro) ``` WeaverAuthController (/auth/weaver/app, callback, logout) WeaverOAuthStrategy, WeaverApiUtils, WeaverConfigService WeaverShrLanding (writePostForm, writeLogoutThenService, redirectLocation) CallbackSuffixCompatFilter login_withForm.js → /qy/auth/weaver/app.do logoutHR.js → /qy/auth/weaver/logout.do integration-config-*.json (weaver + oauth) apusic/.../config/web.xml AttackFilter ``` Search: ``` WeaverShrLanding, writeLogoutThenService, /auth/weaver/app CallbackSuffixCompatFilter, AttackFilter, serverNameWhiteList logoutHR.js, ecologyUrl, index2sso.jsp ```