鸿蒙分布式权限管控高级原理:跨设备权限传递/Token验证/安全沙箱/信任链底层机制
·



一、前置思考
分布式场景下权限管控是最棘手的安全问题——手机上授权的权限,流转到平板上是否自动生效?第三方应用调用分布式摄像头时,权限如何验证?跨设备的accessToken是怎么生成和传递的?
本文聚焦:
- HarmonyOS分布式权限模型(ATAM:Access Token Authentication Mechanism)
- 跨设备权限传递的Token生命周期
- 权限等级DLP(Distributed Level Permission)的设计
- 安全沙箱与进程隔离在分布式场景下的扩展
真实痛点场景:
- 流转后权限丢失:手机上有相机权限,流转到平板后提示"无权限"
- 权限泄露:第三方应用通过分布式调用获取了不应有的传感器数据
- Token过期:长时间使用的分布式能力突然失效
- 权限校验不一致:不同设备上同一个应用权限检查结果不同
二、核心原理
2.1 分布式权限模型
┌─────────────────────────────────────────┐
│ ATAM 权限模型 │
│ │
│ ┌──────────────────────────────────┐ │
│ │ accessToken (AT) │ │
│ │ ┌──────────────────────────┐ │ │
│ │ │ tokenId (唯一ID) │ │ │
│ │ │ bundleName (应用包名) │ │ │
│ │ │ appId (应用标识) │ │ │
│ │ │ userId (用户ID) │ │ │
│ │ │ deviceId (签发设备) │ │ │
│ │ │ authStatus (认证状态) │ │ │
│ │ │ permList (权限列表) │ │ │
│ │ │ expireTime (过期时间) │ │ │
│ │ │ signature (数字签名) │ │ │
│ │ └──────────────────────────┘ │ │
│ └──────────────────────────────────┘ │
│ │
│ 权限等级: │
│ • system_grant → 系统自动授权 │
│ • user_grant → 用户弹窗确认 │
│ • distributed → 额外要求分布式许可 │
│ • restricted → 仅系统应用可申请 │
└─────────────────────────────────────────┘
2.2 分布式权限传递流程
源设备(手机) 目标设备(平板)
│ │
│ 1. 应用调用分布式能力 │
│ (如 distributedCamera) │
│ │
│ 2. 系统检查 accessToken │
│ 确认该应用有 CAMERA 权限 │
│ │
│ 3. 生成分布式Token │
│ (包含原有权限 + 分布式标记) │
│ │
│ 4. Token通过安全信道传输 ──────────→ │
│ │ 5. 目标设备校验Token
│ │ • 验证数字签名
│ │ • 检查权限有效性
│ │ • 确认设备信任关系
│ │
│ │ 6. 校验通过 → 授予临时权限
│ │ 校验失败 → 拒绝请求
│ │
│ 7. 收到确认/拒绝 ←──────────────── │
│ │
│ 8. 分布式能力调用开始 │ 9. 临时权限生效
▼ ▼
2.3 权限等级详解
| 级别 | 含义 | 分布式行为 | 示例权限 |
|---|---|---|---|
normal |
普通权限 | 本地设备有效 | ohos.permission.INTERNET |
system_basic |
系统基础权限 | 同一账号设备间自动传递 | ohos.permission.DISTRIBUTED_DATASYNC |
system_core |
系统核心权限 | 需设备间额外信任验证 | 分发能力受限 |
user_grant |
用户授权 | 每台设备需单独用户确认 | ohos.permission.CAMERA |
distributed |
分布式专用 | 需在源端和目标端同时声明 | 跨设备摄像头共享 |
// module.json5 中的分布式权限声明
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.CAMERA",
"reason": "$string:camera_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC",
"reason": "$string:dist_data_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.DISTRIBUTED_SOFTBUS_CENTER",
"reason": "$string:softbus_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
]
}
}
2.4 动态权限检查
import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
class DistributedPermissionChecker {
private atm: abilityAccessCtrl.AtManager;
constructor() {
this.atm = abilityAccessCtrl.createAtManager();
}
// 检查本地权限
async checkLocalPermission(permission: Permissions): Promise<boolean> {
try {
const grantStatus: abilityAccessCtrl.GrantStatus =
await this.atm.checkAccessToken(
/* accessTokenId */,
permission
);
return grantStatus ===
abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
} catch (e) {
console.error('权限检查失败: ' + (e as Error).message);
return false;
}
}
// 检查分布式权限(验证Token是否有效)
async checkDistributedPermission(
remoteToken: string,
permission: Permissions
): Promise<boolean> {
// 1. 验证Token签名
const verified: boolean = await this.verifyTokenSignature(remoteToken);
if (!verified) return false;
// 2. 解析Token内容
const tokenInfo: TokenInfo = this.parseToken(remoteToken);
// 3. 检查权限是否在Token的permList中
const hasPermission: boolean = this.hasPermissionInToken(
tokenInfo, permission);
// 4. 检查Token是否过期
const isExpired: boolean = Date.now() > tokenInfo.expireTime;
return hasPermission && !isExpired;
}
// 请求用户授权(user_grant权限)
async requestPermissionFromUser(
context: Context,
permissions: Permissions[]
): Promise<void> {
const result: abilityAccessCtrl.GrantStatus =
await this.atm.requestPermissionsFromUser(context, permissions as Array<Permissions>);
// 处理结果...
}
}
interface TokenInfo {
tokenId: string;
bundleName: string;
permList: string[];
expireTime: number;
signature: string;
}
2.5 安全沙箱与分布式隔离
// 分布式场景下的安全沙箱约束
class DistributedSandboxConstraint {
// 分布式调用的文件访问限制
// 只能访问 /data/storage/el2/distributedfiles/
static readonly DISTRIBUTED_FILE_ROOT: string =
'/data/storage/el2/distributedfiles/';
// 分布式调用的API白名单
static readonly DISTRIBUTED_API_WHITELIST: string[] = [
'distributedKVStore',
'distributedDataObject',
'distributedFileSystem',
'distributedScreen',
'distributedCamera',
'distributedSensor'
];
static isDistributedAPIAccessible(apiName: string): boolean {
for (let i: number = 0; i < this.DISTRIBUTED_API_WHITELIST.length; i++) {
if (apiName === this.DISTRIBUTED_API_WHITELIST[i]) {
return true;
}
}
return false;
}
}
三、避坑速查
| 坑 | 现象 | 原因 | 解决 |
|---|---|---|---|
| user_grant未声明reason | 编译报错 | user_grant权限必须提供reason字段 | module.json5中补全reason+usedScene |
| 分布式权限不自动传递 | 流转后无权限 | 不是所有权限都支持分布式传递 | 使用system_basic或distributed级别权限 |
| Token过期 | 长时间运行后权限失效 | Token默认有时效(通常24h) | 在Token过期前主动续期 |
| 设备信任链断裂 | 换新设备后无法分布式调用 | 设备间信任关系基于PIN/账号 | 重新建立设备信任(碰一碰/扫二维码) |
| 动态权限弹窗不弹出 | 调用需要用户确认但无弹窗 | 未在UIAbility的onForeground中请求 | 确保在Activity上下文中调用requestPermissionsFromUser |
| 权限检查返回-1 | 不支持的权限字符 | 拼写错误或API version不支持 | 检查权限名拼写,确认API Level版本 |
| 多用户权限混乱 | 切换账号后权限失效 | accessToken与userId绑定 | 账号切换时重新初始化权限Token |
| 调试设备权限 | 测试机可以但真机不行 | 调试模式自动授予所有权限 | 真机测试必须完整走权限申请流程 |
四、总结
分布式权限管控是鸿蒙安全架构的基石:
- ATAM模型:accessToken = 身份+权限+时效+签名的综合体
- 分布式Token:源端签发,目标端验证,加密信道传递
- 权限等级:system_grant自动传,user_grant需确认,distributed额外要求
- 安全沙箱:分布式调用限制在API白名单和文件沙箱内
更多推荐




所有评论(0)