docs: refine wechat auth design and plan
This commit is contained in:
@@ -32,6 +32,8 @@ The mini program currently supports phone number plus SMS code login only. The n
|
||||
- The current backend issues JWT plus Redis-backed access/refresh tokens through `AuthServiceImpl`.
|
||||
- The mini program manifest already has a WeChat appid: `wxaf2eaba72d28f0e4`.
|
||||
- `application.yml` security ignore URLs must include the new public WeChat login endpoint, while the phone binding endpoint must remain protected by JWT.
|
||||
- `UserInfoResponse` exposes phone, nickname, and avatar, but it does not expose whether the current account has a WeChat binding. The frontend needs a non-sensitive `wechatBound` boolean instead of receiving openid.
|
||||
- Binding an openid from a temporary WeChat user to an existing phone user must also transfer or preserve data created under the temporary user; otherwise early actions before phone binding can be stranded on the temporary account.
|
||||
|
||||
## Recommended Approach
|
||||
|
||||
@@ -62,6 +64,12 @@ Add configuration under `emotion.wechat.mini-program`:
|
||||
|
||||
Secrets must come from environment/profile configuration in deploy environments. `app-secret` must not be sent to the client or logged.
|
||||
|
||||
Add a database migration for WeChat identity integrity:
|
||||
|
||||
- Add a unique composite index on `t_user(third_party_type, third_party_id)`.
|
||||
- MySQL allows multiple `NULL` values in a unique index, so ordinary phone users without WeChat binding are unaffected.
|
||||
- Before transferring an openid from a temporary WeChat user to an existing phone user, clear the temporary user's third-party fields so the unique index remains valid.
|
||||
|
||||
### DTOs
|
||||
|
||||
Add request/response DTOs:
|
||||
@@ -75,6 +83,7 @@ Add request/response DTOs:
|
||||
- `code`: required phone authorization code from `getPhoneNumber`.
|
||||
|
||||
- The response can reuse `AuthResponse` for login and phone binding so token handling stays consistent.
|
||||
- Extend `UserInfoResponse` with `wechatBound: boolean`. It must be computed from the server-side third-party fields and must not expose openid or session key.
|
||||
|
||||
### Service Boundaries
|
||||
|
||||
@@ -85,6 +94,13 @@ Add `WechatMiniProgramService` for WeChat API calls:
|
||||
- `getPhoneNumber(phoneCode)` returns the verified phone number.
|
||||
- Translate WeChat API error codes into clear `BusinessException` messages.
|
||||
|
||||
Add `UserIdentityMergeService` for account convergence:
|
||||
|
||||
- `mergeTemporaryWechatUserIntoPhoneUser(String temporaryWechatUserId, String phoneUserId)` transfers user-owned rows from the temporary WeChat user to the canonical phone user.
|
||||
- The service updates the core mini-program tables that store `user_id`: `t_user_profile`, `t_life_event`, `t_epic_script`, `t_life_path`, `t_life_path_step`, `t_social_content_item`, `t_social_profile_insight`, `t_user_consent_log`, `t_tts_task`, and `t_analytics_event`.
|
||||
- It also updates user-facing shared data where appropriate: `t_conversation`, `t_message`, `t_coze_api_call`, `t_emotion_analysis`, `t_emotion_record`, `t_diary_post`, `t_diary_comment`, `t_community_post`, `t_comment`, `t_user_stats`, and `t_ai_call_log`.
|
||||
- If both users have a singleton row such as `t_user_profile` or `t_user_stats`, keep the existing phone user's row and only transfer rows that do not conflict. This avoids overwriting a mature phone account with sparse temporary data.
|
||||
|
||||
Extend `AuthService` with:
|
||||
|
||||
- `wechatLogin(WechatLoginRequest request)`
|
||||
@@ -122,8 +138,9 @@ For phone binding:
|
||||
4. Query existing user by phone.
|
||||
5. If no phone user exists, set current user's `phone` and mark verified.
|
||||
6. If the phone user is the current user, ensure openid and phone are both present.
|
||||
7. If another enabled user owns the phone, bind the openid to that phone user and issue new tokens for the phone user.
|
||||
7. If another enabled user owns the phone, treat that phone user as canonical.
|
||||
8. If the phone user already has a different WeChat openid, reject with a clear "phone already bound to another WeChat account" message.
|
||||
9. If the phone user can accept the binding, transfer user-owned rows from the temporary WeChat user to the phone user, clear the temporary user's third-party fields, bind the openid to the phone user, and issue new tokens for the phone user.
|
||||
|
||||
When the phone belongs to an existing account, the existing account is the canonical identity. The response must return tokens for that account so future openid login lands on the same user as phone SMS login.
|
||||
|
||||
@@ -152,8 +169,9 @@ Both methods store returned tokens exactly like existing `login()` and `refreshT
|
||||
|
||||
Add to `mini-program/src/stores/app.js`:
|
||||
|
||||
- `wechatLogin(profilePayload)`
|
||||
- `loginWithWechat(profilePayload)`
|
||||
- `bindWechatPhone(phoneCode)`
|
||||
- `fetchCurrentUserInfo()`, called after login, token restore, and phone binding.
|
||||
- Keep `login(phone, smsCode)` unchanged.
|
||||
- After phone binding returns new tokens, refresh current profile/user state.
|
||||
|
||||
@@ -161,7 +179,7 @@ Add to `mini-program/src/stores/app.js`:
|
||||
|
||||
Add a small phone-bind entry in the logged-in experience, preferably in `MineView.vue` or onboarding completion area:
|
||||
|
||||
- Show only when logged in and `userInfo/userProfile` has no phone.
|
||||
- Show only when logged in, `userInfo.phone` is empty, and `userInfo.wechatBound` is true.
|
||||
- Use WeChat `button open-type="getPhoneNumber"` on mp-weixin.
|
||||
- On non-WeChat/H5 builds, show the existing phone SMS login/bind fallback.
|
||||
- If authorization succeeds and backend returns tokens for an existing phone user, overwrite local tokens and refresh profile.
|
||||
@@ -185,6 +203,8 @@ Use WeChat's current nickname/avatar collection pattern in profile or onboarding
|
||||
- Phone authorization denied: do not log out; show a non-blocking message that the user can bind a phone later in the profile center.
|
||||
- Phone API unavailable or permission not enabled: keep openid login active and route user normally.
|
||||
- Existing phone is bound to another openid: reject binding and ask user to use phone login or contact support.
|
||||
- Existing phone account has data while temporary WeChat account also has data: transfer non-conflicting temporary rows to the phone account before switching tokens.
|
||||
- Temporary WeChat account after successful merge: clear its `third_party_type` and `third_party_id` and disable it from future WeChat login matching.
|
||||
- Network failures: preserve current session restore behavior and avoid clearing tokens unless backend explicitly rejects auth.
|
||||
|
||||
## Data Flow
|
||||
@@ -207,8 +227,9 @@ Use WeChat's current nickname/avatar collection pattern in profile or onboarding
|
||||
4. Backend exchanges code for phone number.
|
||||
5. Backend finds existing user by phone.
|
||||
6. Backend binds openid to the phone user or writes phone to current user.
|
||||
7. Backend returns `AuthResponse`.
|
||||
8. Mini program replaces tokens and refreshes user/profile state.
|
||||
7. If an existing phone user is canonical, backend transfers non-conflicting temporary user data and clears the temporary WeChat identity.
|
||||
8. Backend returns `AuthResponse`.
|
||||
9. Mini program replaces tokens and refreshes user/profile state.
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -218,10 +239,13 @@ Backend:
|
||||
- WeChat login returns the same user for a known openid.
|
||||
- Phone binding writes phone to current WeChat user when no existing phone user exists.
|
||||
- Phone binding binds openid to an existing phone user and returns that user's tokens.
|
||||
- Phone binding transfers temporary WeChat user data to the existing phone user before returning phone-user tokens.
|
||||
- Temporary WeChat user no longer matches future openid login after a successful transfer.
|
||||
- Phone binding rejects a phone user already bound to a different openid.
|
||||
- Existing phone SMS login still works.
|
||||
- Token validation and refresh still work after WeChat login.
|
||||
- `/api/auth/wechat/login` is public, and `/api/auth/wechat/phone` rejects unauthenticated requests.
|
||||
- `UserInfoResponse` returns `wechatBound` without returning openid.
|
||||
|
||||
Mini program:
|
||||
|
||||
@@ -232,6 +256,7 @@ Mini program:
|
||||
- Denying phone authorization does not break logged-in state.
|
||||
- Successful phone authorization refreshes tokens and profile.
|
||||
- Personal center reflects nickname/avatar/phone state where available.
|
||||
- Restored sessions fetch current user info so phone binding visibility is correct after app restart.
|
||||
|
||||
## References
|
||||
|
||||
|
||||
Reference in New Issue
Block a user