HarmonyOS开发:系统权限提升——system与core权限

举报
Jack20 发表于 2026/06/28 21:12:06 2026/06/28
【摘要】 HarmonyOS开发:系统权限提升——system与core权限📌 核心要点:鸿蒙的权限不是"申请了就有",而是分级的——normal、system、system_core三级权限对应不同的签名门槛,搞不清分级就等着满屏Permission denied。 背景与动机你写了个系统应用,声明了一堆权限,结果运行的时候一半权限报"denied"。你明明有系统签名啊,为啥还不给?因为你申请的...

HarmonyOS开发:系统权限提升——system与core权限

📌 核心要点:鸿蒙的权限不是"申请了就有",而是分级的——normal、system、system_core三级权限对应不同的签名门槛,搞不清分级就等着满屏Permission denied。

背景与动机

你写了个系统应用,声明了一堆权限,结果运行的时候一半权限报"denied"。你明明有系统签名啊,为啥还不给?

因为你申请的那些权限里,有些是system级别的,有些是system_core级别的。系统签名只够用system级别的权限,system_core级别的权限需要平台签名才行。

这就好比你有公司的门禁卡,能进办公区,但进不了机房——机房需要更高级别的权限卡。

鸿蒙的权限分级是安全体系的根基。不理解这个分级,你连权限声明都写不对,更别提做系统级开发了。这篇就把权限分级、权限申请、权限提升策略和安全审计讲清楚。

核心原理

权限分级体系

鸿蒙的权限分三个级别:

级别 签名要求 授权方式 典型权限
normal 安装时自动授权 网络访问、振动
system 系统签名 安装时自动授权 设置时间、安装应用
system_core 平台签名 安装时自动授权 卸载应用、写系统设置

注意看"授权方式"那一列——三个级别都是"安装时自动授权"。这意味着一旦你的签名级别够了,权限不需要用户手动授权,安装完就有了。

这也意味着:如果签名级别不够,你声明了也没用,安装时直接拒绝。

权限校验流程

flowchart TD
    A[应用调用API] --> B{API需要权限?}
    B -->|不需要| C[直接执行]
    B -->|需要| D{权限级别?}
    
    D -->|normal| E{已声明权限?}
    D -->|system| F{已声明权限?}
    D -->|system_core| G{已声明权限?}
    
    E -->|| H[检查签名: 任意签名]
    E -->|| I[Permission Denied]
    
    F -->|| J{签名类型 ≥ 系统签名?}
    F -->|| I
    
    G -->|| K{签名类型 ≥ 平台签名?}
    G -->|| I
    
    H --> L[权限通过]
    J -->|| L
    J -->|| I
    K -->|| L
    K -->|| I
    
    classDef check fill:#e3f2fd,stroke:#2196f3,color:#0d47a1
    classDef pass fill:#e8f5e9,stroke:#4caf50,color:#1b5e20
    classDef fail fill:#fce4ec,stroke:#f44336,color:#b71c1c
    classDef level fill:#fff3e0,stroke:#ff9800,color:#e65100
    
    class B,D check
    class E,F,G,H,J,K level
    class C,L pass
    class I fail

特权权限列表

常用的systemsystem_core级别权限:

system级别(系统签名即可)

权限 说明
ohos.permission.SET_TIME 设置系统时间
ohos.permission.SET_TIME_ZONE 设置时区
ohos.permission.INSTALL_BUNDLE 安装应用
ohos.permission.GET_BUNDLE_INFO_PRIVILEGED 获取应用详细信息
ohos.permission.MANAGE_LOCAL_ACCOUNTS 管理本地账号
ohos.permission.CONNECTIVITY_INTERNAL 网络管理内部接口

system_core级别(需要平台签名)

权限 说明
ohos.permission.UNINSTALL_BUNDLE 卸载应用
ohos.permission.WRITE_SYSTEM_SETTINGS 写入系统设置
ohos.permission.FACTORY_RESET 恢复出厂设置
ohos.permission.REBOOT 重启设备
ohos.permission.MANAGE_USB USB管理
ohos.permission.UPDATE_SYSTEM 系统更新

权限提升策略

有时候你的应用只有系统签名,但某个功能需要system_core权限。怎么办?

有三种策略:

  1. 拆分应用:把需要system_core权限的功能拆到另一个有平台签名的应用里,通过IPC调用
  2. SA代理:把需要system_core权限的操作封装成SA,SA运行在有平台签名的系统进程里
  3. 权限临时提升:通过AccessTokenManager临时申请更高权限(需要系统签名+用户确认)
flowchart LR
    A[系统签名应用] -->|需要core权限| B{选择策略}
    
    B -->|拆分应用| C[平台签名应用]
    C -->|IPC调用| D[执行core操作]
    
    B -->|SA代理| E[平台签名SA]
    E -->|samgr| D
    
    B -->|临时提升| F[AccessTokenManager]
    F -->|用户确认| G[临时core权限]
    G --> D
    
    classDef problem fill:#fce4ec,stroke:#f44336,color:#b71c1c
    classDef strategy fill:#e3f2fd,stroke:#2196f3,color:#0d47a1
    classDef solution fill:#e8f5e9,stroke:#4caf50,color:#1b5e20
    
    class A problem
    class B,C,E,F strategy
    class D,G solution

代码实战

基础用法:权限声明与检查

// common/PermissionManager.ets - 权限管理工具
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';
import { BusinessError } from '@ohos.base';

class PermissionManager {
  private tag: string = 'PermissionManager';

  // 检查单个权限是否已授权
  async checkPermission(permission: Permissions): Promise<boolean> {
    try {
      const atManager = abilityAccessCtrl.createAtManager();
      const bundleInfo = await bundleManager.getBundleInfoForSelf(
        bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT
      );
      const tokenID = bundleInfo.appInfo.accessTokenId;
      
      const result = await atManager.checkAccessToken(tokenID, permission);
      return result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
    } catch (err) {
      const error = err as BusinessError;
      console.error(this.tag, `检查权限失败: ${error.message}`);
      return false;
    }
  }

  // 批量检查权限
  async checkPermissions(permissions: Permissions[]): Promise<Map<Permissions, boolean>> {
    const resultMap = new Map<Permissions, boolean>();
    for (const permission of permissions) {
      const granted = await this.checkPermission(permission);
      resultMap.set(permission, granted);
    }
    return resultMap;
  }

  // 请求用户授权(仅对user_grant类型的权限有效)
  async requestPermissions(
    context: Context,
    permissions: Permissions[]
  ): Promise<Map<Permissions, boolean>> {
    const resultMap = new Map<Permissions, boolean>();
    
    try {
      const atManager = abilityAccessCtrl.createAtManager();
      const result = await atManager.requestPermissionsFromUser(context, permissions);
      
      for (let i = 0; i < permissions.length; i++) {
        resultMap.set(permissions[i], result.authResults[i] === 0);
      }
    } catch (err) {
      const error = err as BusinessError;
      console.error(this.tag, `请求权限失败: ${error.message}`);
      permissions.forEach(p => resultMap.set(p, false));
    }
    
    return resultMap;
  }
}

export default new PermissionManager();

进阶用法:权限提升与IPC代理

系统签名应用需要调用system_core权限的API时,通过IPC代理实现:

// common/CorePermissionProxy.ets - core权限代理
import { rpc } from '@ohos.rpc';
import { systemAbilityManager } from '@ohos.systemAbilityManager';

// 定义核心操作SA的ID
const CORE_OPERATION_SA_ID = 0x9002;

// 核心操作请求码
const REQUEST_CODE_UNINSTALL_APP = 100;
const REQUEST_CODE_FACTORY_RESET = 101;
const REQUEST_CODE_REBOOT = 102;
const REQUEST_CODE_WRITE_SETTINGS = 103;

class CorePermissionProxy {
  private tag: string = 'CorePermissionProxy';
  private proxy: rpc.IRemoteObject | null = null;

  // 获取核心操作SA的代理
  async getProxy(): Promise<rpc.IRemoteObject | null> {
    if (this.proxy) {
      return this.proxy;
    }

    try {
      this.proxy = await systemAbilityManager.getSystemAbility(CORE_OPERATION_SA_ID);
      return this.proxy;
    } catch (err) {
      console.error(this.tag, `获取代理失败: ${JSON.stringify(err)}`);
      return null;
    }
  }

  // 通过SA代理卸载应用(system_core权限操作)
  async uninstallApp(bundleName: string): Promise<boolean> {
    const proxy = await this.getProxy();
    if (!proxy) {
      console.error(this.tag, '代理不可用');
      return false;
    }

    try {
      const option = new rpc.MessageOption();
      const data = new rpc.MessageSequence();
      const reply = new rpc.MessageSequence();

      // 写入请求码和参数
      data.writeInt(REQUEST_CODE_UNINSTALL_APP);
      data.writeString(bundleName);

      await proxy.sendMessageRequest(0, data, reply, option);
      const success = reply.readInt();
      return success === 1;
    } catch (err) {
      console.error(this.tag, `卸载应用失败: ${JSON.stringify(err)}`);
      this.proxy = null; // 清除可能失效的代理
      return false;
    }
  }

  // 通过SA代理写入系统设置(system_core权限操作)
  async writeSystemSetting(key: string, value: string): Promise<boolean> {
    const proxy = await this.getProxy();
    if (!proxy) {
      return false;
    }

    try {
      const option = new rpc.MessageOption();
      const data = new rpc.MessageSequence();
      const reply = new rpc.MessageSequence();

      data.writeInt(REQUEST_CODE_WRITE_SETTINGS);
      data.writeString(key);
      data.writeString(value);

      await proxy.sendMessageRequest(0, data, reply, option);
      const success = reply.readInt();
      return success === 1;
    } catch (err) {
      console.error(this.tag, `写入设置失败: ${JSON.stringify(err)}`);
      this.proxy = null;
      return false;
    }
  }

  // 通过SA代理重启设备(system_core权限操作)
  async rebootDevice(reason: string): Promise<boolean> {
    const proxy = await this.getProxy();
    if (!proxy) {
      return false;
    }

    try {
      const option = new rpc.MessageOption();
      const data = new rpc.MessageSequence();
      const reply = new rpc.MessageSequence();

      data.writeInt(REQUEST_CODE_REBOOT);
      data.writeString(reason);

      await proxy.sendMessageRequest(0, data, reply, option);
      return true; // 如果能收到回复说明重启还没执行
    } catch (err) {
      // 重启可能导致IPC断开,这其实是正常行为
      console.info(this.tag, '设备正在重启...');
      return true;
    }
  }
}

export default new CorePermissionProxy();

完整示例:权限审计面板

// pages/PermissionAuditPage.ets - 权限审计面板
import PermissionManager from '../common/PermissionManager';
import { Permissions } from '@ohos.abilityAccessCtrl';
import promptAction from '@ohos.promptAction';

interface PermissionInfo {
  name: string;
  level: string;
  description: string;
}

@Entry
@Component
struct PermissionAuditPage {
  @State permissionResults: Map<string, boolean> = new Map();
  @State isAuditing: boolean = false;

  // 需要审计的权限列表
  private auditPermissions: PermissionInfo[] = [
    { name: 'ohos.permission.SET_TIME', level: 'system', description: '设置系统时间' },
    { name: 'ohos.permission.SET_TIME_ZONE', level: 'system', description: '设置时区' },
    { name: 'ohos.permission.INSTALL_BUNDLE', level: 'system', description: '安装应用' },
    { name: 'ohos.permission.GET_BUNDLE_INFO_PRIVILEGED', level: 'system', description: '获取应用详情' },
    { name: 'ohos.permission.UNINSTALL_BUNDLE', level: 'system_core', description: '卸载应用' },
    { name: 'ohos.permission.WRITE_SYSTEM_SETTINGS', level: 'system_core', description: '写入系统设置' },
    { name: 'ohos.permission.FACTORY_RESET', level: 'system_core', description: '恢复出厂设置' },
    { name: 'ohos.permission.REBOOT', level: 'system_core', description: '重启设备' },
  ];

  async aboutToAppear() {
    await this.runAudit();
  }

  // 执行权限审计
  async runAudit() {
    this.isAuditing = true;
    this.permissionResults = new Map();

    for (const perm of this.auditPermissions) {
      const granted = await PermissionManager.checkPermission(perm.name as Permissions);
      this.permissionResults.set(perm.name, granted);
    }

    this.isAuditing = false;
  }

  // 统计权限通过率
  getPassRate(): string {
    let total = 0;
    let passed = 0;
    this.permissionResults.forEach((granted, _) => {
      total++;
      if (granted) passed++;
    });
    return total === 0 ? '0%' : `${Math.round(passed / total * 100)}%`;
  }

  // 按级别统计
  getLevelStats(level: string): { total: number; passed: number } {
    let total = 0;
    let passed = 0;
    this.auditPermissions
      .filter(p => p.level === level)
      .forEach(p => {
        total++;
        if (this.permissionResults.get(p.name)) passed++;
      });
    return { total, passed };
  }

  build() {
    Scroll() {
      Column() {
        // 审计概览
        Row() {
          Column() {
            Text('权限通过率')
              .fontSize(12)
              .fontColor('#999999')
            Text(this.getPassRate())
              .fontSize(28)
              .fontWeight(FontWeight.Bold)
              .fontColor('#1976d2')
          }
          .alignItems(HorizontalAlign.Center)

          Divider()
            .vertical(true)
            .height(40)
            .color('#e0e0e0')
            .margin({ left: 24, right: 24 })

          Column() {
            const sysStats = this.getLevelStats('system');
            Text('system权限')
              .fontSize(12)
              .fontColor('#999999')
            Text(`${sysStats.passed}/${sysStats.total}`)
              .fontSize(20)
              .fontWeight(FontWeight.Bold)
              .fontColor('#ff9800')
          }
          .alignItems(HorizontalAlign.Center)

          Divider()
            .vertical(true)
            .height(40)
            .color('#e0e0e0')
            .margin({ left: 24, right: 24 })

          Column() {
            const coreStats = this.getLevelStats('system_core');
            Text('system_core权限')
              .fontSize(12)
              .fontColor('#999999')
            Text(`${coreStats.passed}/${coreStats.total}`)
              .fontSize(20)
              .fontWeight(FontWeight.Bold)
              .fontColor('#f44336')
          }
          .alignItems(HorizontalAlign.Center)
        }
        .width('100%')
        .justifyContent(FlexAlign.Center)
        .padding(20)
        .backgroundColor('#ffffff')
        .borderRadius(12)
        .margin({ bottom: 16 })

        // system级别权限
        Column() {
          Text('system级别权限')
            .fontSize(16)
            .fontWeight(FontWeight.Bold)
            .margin({ bottom: 12 })

          ForEach(
            this.auditPermissions.filter(p => p.level === 'system'),
            (perm: PermissionInfo) => {
              this.PermissionRow(perm)
            },
            (perm: PermissionInfo) => perm.name
          )
        }
        .width('100%')
        .padding(16)
        .backgroundColor('#ffffff')
        .borderRadius(12)
        .margin({ bottom: 16 })

        // system_core级别权限
        Column() {
          Text('system_core级别权限')
            .fontSize(16)
            .fontWeight(FontWeight.Bold)
            .margin({ bottom: 12 })

          ForEach(
            this.auditPermissions.filter(p => p.level === 'system_core'),
            (perm: PermissionInfo) => {
              this.PermissionRow(perm)
            },
            (perm: PermissionInfo) => perm.name
          )
        }
        .width('100%')
        .padding(16)
        .backgroundColor('#ffffff')
        .borderRadius(12)
        .margin({ bottom: 16 })

        // 操作按钮
        Button('重新审计')
          .width('100%')
          .height(48)
          .backgroundColor('#1976d2')
          .borderRadius(8)
          .enabled(!this.isAuditing)
          .onClick(() => this.runAudit())
      }
      .padding(24)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#f5f5f5')
  }

  @Builder
  PermissionRow(perm: PermissionInfo) {
    Row() {
      Column() {
        Text(perm.description)
          .fontSize(14)
          .fontColor('#333333')
        Text(perm.name)
          .fontSize(11)
          .fontColor('#999999')
          .margin({ top: 2 })
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      Text(this.permissionResults.get(perm.name) ? '已授权' : '未授权')
        .fontSize(13)
        .fontColor(this.permissionResults.get(perm.name) ? '#4caf50' : '#f44336')
        .padding({ left: 8, right: 8, top: 4, bottom: 4 })
        .backgroundColor(this.permissionResults.get(perm.name) ? '#e8f5e9' : '#fce4ec')
        .borderRadius(4)
    }
    .width('100%')
    .margin({ bottom: 10 })
  }
}

踩坑与注意事项

坑一:权限声明了但签名级别不够

这是最常见的问题。你在module.json5里声明了ohos.permission.UNINSTALL_BUNDLE(system_core级别),但你的应用只有系统签名(不够platform签名),安装时这个权限直接被忽略,调用API时报Permission denied。

而且这个报错信息不会告诉你"签名级别不够",只会说"Permission denied"。你得自己查权限级别表,判断是签名不够还是声明遗漏。

坑二:混淆system和system_core

有些权限的级别在不同HarmonyOS版本之间发生了变化。比如INSTALL_BUNDLE在早期版本是system_core级别,后来降级为system级别。如果你的代码是基于旧文档写的,可能判断有误。

务必以当前版本的权限定义文件为准,不要依赖过时的文档。

坑三:权限审计遗漏

你的应用声明了20个权限,但实际只用了15个。多出来的5个权限是安全风险——万一有漏洞被利用,攻击者能通过这些多余权限做更多事。

定期做权限审计,把不需要的权限删掉。原则是:最小权限原则,只声明必须的权限。

坑四:IPC代理的安全性

通过SA代理调用system_core权限的操作时,SA本身不做调用者校验——任何能拿到SA代理的进程都能调用。这意味着如果你的SA暴露了卸载应用的接口,恶意应用也能通过这个接口卸载其他应用。

解决办法:在SA里校验调用者的身份:

// 在SA的OnRemoteRequest中校验调用者
OnRemoteRequest(code: number, data: rpc.MessageSequence, reply: rpc.MessageSequence,
                option: rpc.MessageOption): boolean {
  // 校验调用者是否为受信任的应用
  const callerTokenId = rpc.getCallingTokenId();
  if (!this.isTrustedCaller(callerTokenId)) {
    console.error(this.tag, `不受信任的调用者: ${callerTokenId}`);
    reply.writeInt(0); // 返回失败
    return true;
  }

  // 校验通过,执行操作
  switch (code) {
    case REQUEST_CODE_UNINSTALL_APP:
      // 执行卸载操作
      break;
  }
  return true;
}

// 检查调用者是否受信任
isTrustedCaller(tokenId: number): boolean {
  // 检查调用者的包名是否在白名单中
  // 或者检查调用者是否有系统签名
  return true; // 简化示例
}

坑五:权限声明格式错误

module.json5里的权限声明格式必须严格正确。常见错误:

// 错误:权限名拼写错误
{ "name": "ohos.permission.set_time" }  // 小写,应该是大写

// 错误:权限对象缺少必要字段
{ "name": "ohos.permission.SET_TIME" }  // 缺少reason和usedScene

// 正确:完整的权限声明
{
  "name": "ohos.permission.SET_TIME",
  "reason": "$string:permission_reason",
  "usedScene": {
    "abilities": ["MainAbility"],
    "when": "inuse"
  }
}

HarmonyOS 6适配说明

HarmonyOS 6在权限体系方面有几个重要变化:

  1. 权限级别新增restricted:在systemsystem_core之间新增了restricted级别,用于特别敏感的操作(如生物识别、位置精确定位)。restricted权限需要系统签名+用户确认。

  2. 权限声明必须包含reason:所有system及以上级别的权限声明必须包含reason字段和usedScene字段,否则安装时拒绝。之前这个只是推荐,现在变成强制。

  3. 权限使用追踪:系统会记录每个权限的使用时间和频率。如果某个权限长时间未使用,系统会提示用户回收。这对系统应用也适用。

  4. 权限沙箱增强:即使有system_core权限,系统应用也不能随意访问其他应用的数据。需要通过DataShare接口按规则访问。

适配建议:检查所有权限声明是否包含reasonusedScene,清理不必要的权限声明,新增的restricted权限按需申请。

总结

权限分级是鸿蒙安全体系的基石。normalsystemsystem_core三级权限对应不同的签名门槛,搞不清分级就写不对权限声明。

核心要点回顾:

  • system权限需要系统签名,system_core权限需要平台签名
  • 权限声明和签名必须匹配,缺一不可
  • 不够签名级别时,通过SA代理或拆分应用实现权限提升
  • IPC代理要做调用者校验,防止权限泄露
  • 定期做权限审计,遵循最小权限原则
维度 评价
学习难度 ⭐⭐⭐⭐ 权限分级体系不复杂,但权限列表多、版本变化多
使用频率 ⭐⭐⭐⭐⭐ 做系统级开发必用,每个系统应用都要处理权限
重要程度 ⭐⭐⭐⭐⭐ 安全的核心,权限管理出错可能导致安全漏洞
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。