在这里插入图片描述
在这里插入图片描述

一、前置思考

1.1 跨设备传文件是高频刚需,也是最容易泄露的环节

文档从手机传给平板、会议投屏分享文件、协同编辑共享素材……跨设备文件共享需求无处不在。但实现方式天差地别:

❌ 方案1: 上传到公共服务器中转 → 慢 + 数据出设备 + 隐私风险
❌ 方案2: 蓝牙/热点直传 → 速度慢 + 兼容性差
❌ 方案3: 直接给其他应用永久读写路径 → 安全后门
✅ 方案4: 分布式文件共享 + URI 临时授权 + 生命周期管控

1.2 共享的三个核心矛盾

矛盾 说明
方便 vs 安全 越方便越容易泄露
共享 vs 回收 共享出去要能收回来
实时 vs 可控 实时同步但要有权限边界

1.3 本文路线

深入分布式文件共享、URI 临时授权、共享时效 Token、生命周期管理四层,给出跨设备文件共享企业方案。

二、核心原理

2.1 分布式文件共享架构

设备A (发起方)                    设备B (接收方)
  │                                    │
  │ 1. 选择文件 (本地/共享目录)          │
  │ 2. 生成共享URI + 授权Token         │
  │ 3. 通过分布式能力传递 ────────────→ │
  │                                    │ 4. 校验 Token 时效/权限
  │                                    │ 5. 按模式访问文件
  │ 6. 生命周期到期/撤销 ←───────────── │ 6. 访问失效

2.2 URI 临时授权模型

授权要素:
  URI      : 指向具体文件 (file://bundle/share/xxx.pdf)
  Mode     : 只读 / 读写
  Token    : 一次性授权凭证 (绑定 URI + 模式 + 时效)
  TTL      : 有效期 (分钟级/小时级)

校验链:
  访问请求 → 携带 URI + Token
  → 系统校验 Token 未过期
  → 校验 Token 与 URI 匹配
  → 校验模式权限 (读/写)
  → 通过 → 放行

2.3 共享时效 Token 机制

Token 生命周期:
  签发: 生成 {fileId, mode, expireAt, scope}
  传递: 随 URI 一起发给接收方
  校验: 每次访问检查 expireAt
  撤销: 主动吊销 → Token 立即失效
  过期: 到达 expireAt → 自动失效

设计要点:
  - Token 不可猜测 (随机数 + 签名)
  - 时效必须短 (默认 30 分钟)
  - 支持提前吊销

2.4 共享生命周期管理

生命周期状态机:
  创建 → 授权中 → 有效 → 过期/撤销 → 归档/删除

管理动作:
  查看: 当前有哪些共享/给谁/何时到期
  续期: 临近过期可续期 (用户确认)
  撤销: 提前终止共享
  删除: 文件删除时级联撤销共享

三、源码/API 深度解析

3.1 共享授权模型(应用层实现)

interface ShareGrant {
  grantId: string;        // 授权 ID
  fileId: string;         // 文件标识
  fileUri: string;        // 文件 URI
  targetDevice: string;   // 目标设备
  mode: 'read' | 'readwrite';
  expireAt: number;       // 过期时间戳
  revoked: boolean;
}

class ShareGrantStore {
  private grants: Map<string, ShareGrant> = new Map();

  // 签发授权
  issue(grant: ShareGrant): void {
    this.grants.set(grant.grantId, grant);
  }

  // 校验: 是否有效
  verify(grantId: string, now = Date.now()): boolean {
    const g = this.grants.get(grantId);
    if (!g) { return false; }
    if (g.revoked) { return false; }
    if (g.expireAt < now) { return false; }
    return true;
  }

  // 撤销
  revoke(grantId: string): boolean {
    const g = this.grants.get(grantId);
    if (!g) { return false; }
    g.revoked = true;
    return true;
  }

  // 续期
  renew(grantId: string, ttlMs: number): boolean {
    const g = this.grants.get(grantId);
    if (!g || g.revoked) { return false; }
    g.expireAt = Date.now() + ttlMs;
    return true;
  }

  // 清理过期授权
  sweepExpired(now = Date.now()): number {
    let n = 0;
    this.grants.forEach((g, id) => {
      if (g.expireAt < now || g.revoked) { this.grants.delete(id); n++; }
    });
    return n;
  }
}

3.2 分布式文件访问

import { distributedDeviceManager } from '@kit.DistributedServiceKit';
import { fileIo as fs } from '@kit.CoreFileKit';

// 设备发现
async function listPeerDevices(): Promise<string[]> {
  const dm = distributedDeviceManager.createDeviceManager('com.example.app');
  const devices = dm.getAvailableDeviceListSync();
  return devices.map(d => d.deviceName);
}

// 跨设备打开文件 (简化为本机沙箱共享目录, 实际走分布式文件系统)
function openSharedFile(fileUri: string): fs.File {
  // 分布式场景: 通过分布式文件系统挂载路径访问
  return fs.openSync(fileUri, fs.OpenMode.READ_ONLY);
}

3.3 共享会话管理

class ShareSession {
  private grantStore = new ShareGrantStore();
  private expireTimer: number = -1;

  // 创建共享会话
  createShare(fileUri: string, targetDevice: string,
    mode: 'read' | 'readwrite', ttlMs = 30 * 60 * 1000): string {
    const grantId = 'share_' + Date.now() + '_' + Math.floor(Math.random() * 10000);
    this.grantStore.issue({
      grantId: grantId, fileId: fileUri, fileUri: fileUri,
      targetDevice: targetDevice, mode: mode,
      expireAt: Date.now() + ttlMs, revoked: false
    });
    // 启动过期巡检
    this.startSweeper();
    return grantId;
  }

  private startSweeper(): void {
    if (this.expireTimer === -1) {
      this.expireTimer = setInterval(() => {
        this.grantStore.sweepExpired();
      }, 60 * 1000);   // 每分钟清理过期授权
    }
  }

  stop(): void {
    if (this.expireTimer !== -1) {
      clearInterval(this.expireTimer);
      this.expireTimer = -1;
    }
  }
}

四、企业级实战落地

4.1 共享全流程

1. 用户选择文件 → 预览
2. 选择目标设备 (组网设备列表)
3. 选择模式 (只读/可编辑) + 有效期 (10/30/60分钟)
4. 签发授权 → 传递 URI+Token 给目标设备
5. 目标设备校验 → 打开文件
6. 到期自动失效 / 用户手动撤销
7. 共享记录审计 (谁/何时/哪个文件)

4.2 共享记录审计

interface ShareAuditLog {
  time: string;
  file: string;
  target: string;
  mode: string;
  action: 'ISSUE' | 'ACCESS' | 'REVOKE' | 'EXPIRE';
}

// 所有共享动作落审计日志
function audit(log: ShareAuditLog): void {
  // 写入审计存储 (加密)
  console.info(`[共享审计] ${log.time} ${log.action} ${log.file}${log.target} ${log.mode}`);
}

4.3 与会议/协同场景结合

会议投屏: 讲稿只读共享 30 分钟 → 结束后自动撤销
协同编辑: 文档可编辑共享 2 小时 → 到期提醒续期
素材分发: 图片批量共享 10 分钟 → 下载即撤销

4.4 安全等级对照

场景 模式 时效 校验
普通文档查看 只读 30分钟 Token
协同编辑 读写 2小时 Token + 用户认证
敏感文件 只读+水印 10分钟 Token + 设备白名单
一次性素材 只读 5分钟 一次性 Token

五、问题排查与性能优化

现象 原因 解决
文件打不开 目标设备无权 Token 过期/撤销 重新签发
共享失控 授权永久有效 无 TTL 默认短时效
权限越界 只读变可写 模式校验缺失 每次访问校验 mode
共享残留 记录膨胀 不清理 过期巡检
设备断连 传文件失败 组网丢失 重连 + 重发授权
撤销无效 还能访问 未同步撤销 撤销广播到对端
大文件超时 传输中断 无续传 分片 + 续传

5.1 短时效 + 快速续期

默认 30 分钟 → 使用中提醒续期 → 续期重新签发新 Token
(旧 Token 作废, 新 Token 续期, 全程用户可控)

5.2 敏感文件保护增强

只读 + 动态水印 (设备名/时间)
仅限设备白名单
预览而非下载 (不落盘)
到期立即销毁本地缓存副本

5.3 传输性能

大文件: 分片传输 + 断点续传 (见第79篇)
多文件: 批量授权 + 并行传输
弱网: 降级预览 (先传缩略图, 再按需全量)

六、高阶总结与最佳实践

  1. 分布式共享 + 临时授权是跨设备文件的正确姿势,公共服务器中转是下策。
  2. Token 三要素:随机不可猜 + 短时效 + 可撤销,每次访问都校验。
  3. 生命周期状态机:创建→有效→过期/撤销,巡检清理过期授权。
  4. 全程审计:谁、何时、哪个文件、什么模式——共享动作全部留痕。
  5. 敏感分级:按文件敏感度决定模式/时效/水印/白名单。

一句话记住:跨设备共享四件套——URI 定位文件、Token 做凭证、短时效防后门、生命周期管全程;共享给出去的权限,一定要能收回来。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐