feat: 事件详情页 URL ID 加密,防止用户遍历
- 新增 idEncoder.ts 工具:使用 Base64 + 前缀混淆加密 ID - 路由改为查询参数形式:/event-detail?id=xxx - 更新所有入口使用 getEventDetailUrl() 生成加密链接 - 兼容旧链接:纯数字 ID 仍可正常访问 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
55
src/utils/idEncoder.ts
Normal file
55
src/utils/idEncoder.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* ID 加密/解密工具
|
||||
* 用于隐藏 URL 中的真实 ID,防止用户猜测遍历
|
||||
*
|
||||
* 使用 Base64 编码 + 前缀混淆
|
||||
* 例如: 15901 -> "ZXYtMTU5MDE"
|
||||
*/
|
||||
|
||||
const SECRET_PREFIX = 'ev-';
|
||||
|
||||
/**
|
||||
* 加密事件 ID
|
||||
* @param id - 原始 ID
|
||||
* @returns 加密后的字符串
|
||||
*/
|
||||
export const encodeEventId = (id: number | string): string => {
|
||||
if (id === null || id === undefined) return '';
|
||||
return btoa(SECRET_PREFIX + String(id));
|
||||
};
|
||||
|
||||
/**
|
||||
* 解密事件 ID
|
||||
* @param encoded - 加密后的字符串
|
||||
* @returns 原始 ID,解密失败返回 null
|
||||
*/
|
||||
export const decodeEventId = (encoded: string): string | null => {
|
||||
if (!encoded) return null;
|
||||
|
||||
try {
|
||||
const decoded = atob(encoded);
|
||||
if (decoded.startsWith(SECRET_PREFIX)) {
|
||||
return decoded.slice(SECRET_PREFIX.length);
|
||||
}
|
||||
// 兼容:如果是纯数字(旧链接),直接返回
|
||||
if (/^\d+$/.test(encoded)) {
|
||||
return encoded;
|
||||
}
|
||||
return null;
|
||||
} catch {
|
||||
// Base64 解码失败,可能是旧的纯数字链接
|
||||
if (/^\d+$/.test(encoded)) {
|
||||
return encoded;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成事件详情页 URL
|
||||
* @param eventId - 事件 ID
|
||||
* @returns 完整路径
|
||||
*/
|
||||
export const getEventDetailUrl = (eventId: number | string): string => {
|
||||
return `/event-detail?id=${encodeEventId(eventId)}`;
|
||||
};
|
||||
Reference in New Issue
Block a user