Proxy 可拦截对象属性读写操作,在 get/set 中结合角色、字段级权限规则实现动态访问控制,支持嵌套对象递归代理和运行时权限更新,但需注意 ownKeys、has 等操作未被默认拦截。

可以用 Proxy 拦截对象的属性读写操作,在 get 和 set 中结合权限规则做动态校验,实现细粒度的访问控制。
定义权限规则和用户角色
先明确哪些用户能读/写哪些属性。常见做法是用一个配置对象描述权限,比如:
- role-based:按角色(如 "admin"、"editor"、"viewer")定义可访问字段列表
-
field-level:每个属性单独配置
read和write的允许角色数组 - 也可结合上下文(如当前登录用户 ID、请求来源)动态判断,不局限于静态角色
用 Proxy 拦截 get/set 操作
创建 Proxy 时,在 get 中检查读权限,set 中检查写权限。未授权时可返回 undefined、抛错或静默忽略:
const permissions = {
name: { read: ['admin', 'editor'], write: ['admin'] },
email: { read: ['admin'], write: ['admin'] },
status: { read: ['admin', 'editor', 'viewer'], write: ['admin', 'editor'] }
};
function createSecureObject(target, userRole) {
return new Proxy(target, {
get(obj, prop) {
const rule = permissions[prop];
if (rule && !rule.read?.includes(userRole)) {
console.warn(`Access denied: ${prop} is not readable by ${userRole}`);
return undefined;
}
return obj[prop];
},
set(obj, prop, value) {
const rule = permissions[prop];
if (rule && !rule.write?.includes(userRole)) {
console.warn(`Write denied: ${prop} is not writable by ${userRole}`);
return false; // 静默失败,或 throw new Error()
}
obj[prop] = value;
return true;
}
});
}
const user = { name: 'Alice', email: 'a@example.com', status: 'active' };
const editorProxy = createSecureObject(user, 'editor');
console.log(editorProxy.name); // 'Alice'
console.log(editorProxy.email); // undefined(无读权限)
editorProxy.status = 'inactive'; // ✅ 允许
editorProxy.email = 'new@ex.com'; // ❌ 拒绝写入
支持动态权限与嵌套对象
若目标对象含嵌套结构,需递归代理或使用 Reflect.get/Reflect.set 保持原语义;权限判断也可从外部函数获取,便于运行时更新:
立即学习“Java免费学习笔记(深入)”;
- 把权限校验逻辑抽成独立函数,例如
canRead(prop, user),方便集成后端权限服务或 RBAC 系统 - 对嵌套属性(如
user.profile.avatar),可在get中检测点号路径,或对子对象也返回 Proxy 实例 - 避免直接暴露原始对象,确保所有访问都经过 Proxy,否则绕过控制
注意事项与边界情况
Proxy 不会拦截属性是否存在(in 操作符)、Object.keys() 或 for...in,这些仍能看到所有键名。如需隐藏字段,需配合 ownKeys 和 has 拦截:
- 覆盖
ownKeys返回过滤后的键数组,影响Object.getOwnPropertyNames等 - 重写
has控制prop in obj的结果 - 注意
JSON.stringify会跳过 Proxy,需自定义toJSON方法或显式解包 - 性能敏感场景慎用,频繁拦截可能带来开销,建议只代理关键数据对象


















