fix(wx): strip identity from share page_path; guard router unionid switch
- Sanitize page_path before router.push (H5) to prevent cross-user login via shared link - onShareAppMessage: remove unionid/openid/status and related query keys from shared path - main.ts: fix login(to.query.toString()) bug; when already logged in, strip foreign unionid from URL instead of logout Made-with: Cursor
This commit is contained in:
+22
-4
@@ -72,12 +72,30 @@ router.beforeEach(async (to, from , next) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
// switched unionid
|
||||
// switched unionid(URL 与当前会话不一致时)
|
||||
if (to.query.unionid && store.unionid !== to.query.unionid) {
|
||||
cookie.set(HtyUnionIDToken, to.query.unionid);
|
||||
const rawQ = to.query.unionid;
|
||||
const qUnionStr = String(Array.isArray(rawQ) ? rawQ[0] : rawQ || '');
|
||||
// 已登录且 URL 中的 unionid 与当前用户不同:多为带毒分享链接,剥离身份参数而非 logout
|
||||
if (store.current.hty_id && qUnionStr) {
|
||||
const cur = store.current as { union_id?: string };
|
||||
const currentUnion = String(
|
||||
cur.union_id != null && cur.union_id !== '' ? cur.union_id : store.unionid || ''
|
||||
);
|
||||
if (currentUnion && qUnionStr !== currentUnion) {
|
||||
const nextQuery = { ...to.query } as Record<string, string | string[] | undefined | null>;
|
||||
delete nextQuery.unionid;
|
||||
delete nextQuery.openid;
|
||||
delete nextQuery.status;
|
||||
await router.replace({ path: to.path, query: nextQuery });
|
||||
next();
|
||||
return;
|
||||
}
|
||||
}
|
||||
cookie.set(HtyUnionIDToken, qUnionStr);
|
||||
logout();
|
||||
await login(to.query.toString())
|
||||
next()
|
||||
await login(qUnionStr);
|
||||
next();
|
||||
return;
|
||||
}
|
||||
let {enabled, is_registered, roles, union_id} = store.current;
|
||||
|
||||
+3
-1
@@ -50,6 +50,7 @@ import {
|
||||
showConfirmDialog,
|
||||
} from "vant";
|
||||
import { CurrentUserRole } from "~/utils";
|
||||
import { sanitizeMiniProgramWebViewPathForRouter } from "~/utils/wxMiniProgramWebViewShare";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@@ -97,7 +98,8 @@ export default defineComponent({
|
||||
|
||||
console.log("page_path...", page_path, decodeURIComponent(page_path))
|
||||
if (page_path) {
|
||||
await router.push(decodeURIComponent(page_path))
|
||||
const inner = sanitizeMiniProgramWebViewPathForRouter(decodeURIComponent(page_path))
|
||||
await router.push(inner)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 小程序 WebView 分享 / page_path 里可能携带上一用户的 unionid、openid、status 等,
|
||||
* 接收方打开后会导致串号或误登。从「路径 + 查询」字符串中剥离这些参数后再交给 vue-router。
|
||||
*/
|
||||
const WEBVIEW_IDENTITY_QUERY_KEYS = [
|
||||
'unionid',
|
||||
'openid',
|
||||
'status',
|
||||
'nickName',
|
||||
'avatarUrl',
|
||||
'ts',
|
||||
'scene',
|
||||
] as const;
|
||||
|
||||
export function sanitizeMiniProgramWebViewPathForRouter(decodedPathOrUrl: string): string {
|
||||
const raw = decodedPathOrUrl.trim();
|
||||
if (!raw || raw === '/') {
|
||||
return '/';
|
||||
}
|
||||
let pathPart = raw;
|
||||
let search = '';
|
||||
const q = raw.indexOf('?');
|
||||
if (q === 0) {
|
||||
pathPart = '/';
|
||||
search = raw.slice(1);
|
||||
} else if (q > 0) {
|
||||
pathPart = raw.slice(0, q) || '/';
|
||||
search = raw.slice(q + 1);
|
||||
}
|
||||
if (!pathPart.startsWith('/')) {
|
||||
pathPart = `/${pathPart}`;
|
||||
}
|
||||
if (!search) {
|
||||
return pathPart;
|
||||
}
|
||||
const params = new URLSearchParams(search);
|
||||
for (const key of WEBVIEW_IDENTITY_QUERY_KEYS) {
|
||||
params.delete(key);
|
||||
}
|
||||
const rest = params.toString();
|
||||
return rest ? `${pathPart}?${rest}` : pathPart;
|
||||
}
|
||||
@@ -211,8 +211,29 @@ Page({
|
||||
onShareAppMessage({from, target, webViewUrl}) {
|
||||
log.info("share", [from, target, webViewUrl].join(" | "))
|
||||
let pathname = webViewUrl.replace(app.globalData.server, '');
|
||||
if (pathname !== '/') {
|
||||
pathname = encodeURIComponent(pathname)
|
||||
// 分享勿带 WebView 入口里的 unionid/openid/status 等,避免接收方串号
|
||||
if (pathname && pathname !== '/') {
|
||||
try {
|
||||
const q = pathname.indexOf('?')
|
||||
let base = pathname
|
||||
let search = ''
|
||||
if (q === 0) {
|
||||
base = '/'
|
||||
search = pathname.slice(1)
|
||||
} else if (q > 0) {
|
||||
base = pathname.slice(0, q) || '/'
|
||||
search = pathname.slice(q + 1)
|
||||
}
|
||||
if (search) {
|
||||
const sp = new URLSearchParams(search)
|
||||
;['unionid', 'openid', 'status', 'nickName', 'avatarUrl', 'ts', 'scene'].forEach((k) => sp.delete(k))
|
||||
const rest = sp.toString()
|
||||
pathname = rest ? `${base}?${rest}` : (base || '/')
|
||||
}
|
||||
} catch (e) {
|
||||
log.info('share strip query skip', e)
|
||||
}
|
||||
pathname = pathname === '/' ? '/' : encodeURIComponent(pathname)
|
||||
}
|
||||
const promise = new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
|
||||
Reference in New Issue
Block a user