OpenHarmony5.0release应用开发基础之应用权限
1、应用权限是什么?为什么需要? 默认情况下,应用只能访问有限的系统资源。但某些情况下,应用存在扩展功能的诉求,需要访问额外的系统数据(包括用户个人数据)和功能,系统也必须以明确的方式对外提供接口来共享其数据或功能。系统通过访问控制的机制,来避免数据或功能被不当或恶意使用。
1、应用权限是什么?为什么需要?
- 默认情况下,应用只能访问有限的系统资源。但某些情况下,应用存在扩展功能的诉求,需要访问额外的系统数据(包括用户个人数据)和功能,系统也必须以明确的方式对外提供接口来共享其数据或功能。系统通过访问控制的机制,来避免数据或功能被不当或恶意使用。当前访问控制的机制涉及多方面,包括应用沙箱、应用权限、系统控件等方案。
- 系统根据应用的APL等级设置进程域和数据域标签,并通过访问控制机制限制应用可访问的数据范围,从而实现在机制上消减应用数据泄露的风险。不同APL等级的应用能够申请的权限等级不同,且不同的系统资源(如:通讯录等)或系统能力(如:访问摄像头、麦克风等)受不同的应用权限保护。通过严格的分层权限保护,有效抵御恶意攻击,确保系统安全可靠。
2、应用APL等级和权限APL等级
为了防止应用过度索取和滥用权限,系统基于APL(Ability Privilege Level,元能力权限等级)等级,配置了不同的权限开放范围。
元能力权限等级APL指的是应用的权限申请优先级的定义,不同APL等级的应用能够申请的权限等级不同。
2.1、应用APL等级
应用的等级可以分为以下三个等级,等级依次提高。
APL级别 | 说明 |
---|---|
normal | 默认情况下,应用的APL等级都为normal等级。 |
system_basic | 该等级的应用服务提供系统基础服务。 |
system_core | 该等级的应用服务提供操作系统核心能力。 应用APL等级不允许配置为system_core。 |
2.2、权限APL等级
根据权限对于不同等级应用有不同的开放范围,权限类型对应分为以下三个等级,等级依次提高。
APL级别 | 说明 | 开放范围 |
---|---|---|
normal | 允许应用访问超出默认规则外的普通系统资源,如配置Wi-Fi信息、调用相机拍摄等。 这些系统资源的开放(包括数据和功能)对用户隐私以及其他应用带来的风险低。 | APL等级为normal及以上的应用。 |
system_basic | 允许应用访问操作系统基础服务(系统提供或者预置的基础功能)相关的资源,如系统设置、身份认证等。 这些系统资源的开放对用户隐私以及其他应用带来的风险较高。 | APL等级为system_basic及以上的应用。 |
system_core | 涉及开放操作系统核心资源的访问操作。这部分系统资源是系统最核心的底层服务,如果遭受破坏,操作系统将无法正常运行。 | - APL等级为system_core的应用。 - 仅对系统应用开放。 |
2.3、解读
我们开发的是应用,应用APL等级如何设置呢?(写完文章过程中发现5.0DevEco还不支持OpenHarmony项目新建,后面以DevEco 4.1Release为例)
应用的实际APL等级是根据编译工具链的配置文件(OpenHarmony\Sdk\11\toolchains\lib\UnsgnedDebugProfileTemplate.json和UnsgnedReleasedProfileTemplate.json)来的,一个对应debug按钮编译产物,一个对应Run按钮编译产物。UnsgnedReleasedProfileTemplate文件如下。
{ "version-name":"2.0.0", "version-code":2, "app-distribution-type":"os_integration", "uuid":"---", "validity":{ "not-before":1594865258, "not-after":1689473258 }, "type":"release", "bundle-info":{ "developer-id":"OpenHarmony", "distribution-certificate":"", "bundle-name":"com", "apl":"system_core", "app-feature":"hos_system_app" }, "acls":{ "allowed-acls":[ "" ] }, "permissions":{ "restricted-permissions":[] }, "issuer":"pki_internal" }
我们可以使用acl使能,也可以修改apl和app-feature字段来实现提权。改成上述文件,应用就是系统应用。
权限APL等级如何设置?权限APL等级是编译时就确定的,已经烧录在系统中,无法直接更改,查看方式为
以这个ohos.permission.CONTROL_LOCATION_SWITCH权限为例,他就是system_core级别的权限,授权方式是system_grant。
3、应用申请权限的步骤
3.1、normal等级应用申请权限的方式
权限类型 | 授权方式 | 操作路径 |
---|---|---|
所有应用可申请 | system_grant | 声明权限 > 访问接口 |
所有应用可申请 | user_grant | 声明权限 > 向用户申请授权 > 访问接口 |
允许normal等级应用通过ACL跨级申请 | system_grant | 声明权限 > 声明ACL权限 > 访问接口 |
允许normal等级应用通过ACL跨级申请 | user_grant | 声明权限 > 声明ACL权限 > 向用户申请授权 > 访问接口 |
说明:
- 如果system_basic等级的权限,ACL使能为false,则normal等级应用无法申请该权限。
- 当前可通过DevEco Studio完成ACL方式跨级别申请权限,但该方法仅用于应用调试阶段使用,不可用于发布上架应用市场。如果需要开发商用版本的应用,请在对应的应用市场进行发布证书和Profile文件的申请。
3.2、system_basic等级应用申请权限的方式
权限等级 | 授权方式 | ACL使能 | 操作路径 |
---|---|---|---|
normal、system_basic | system_grant | - | 声明权限 > 访问接口 |
normal、system_basic | user_grant | - | 声明权限 > 向用户申请授权 > 访问接口 |
system_core | system_grant | true | 声明权限 > 声明ACL权限 > 访问接口 |
system_core | user_grant | true | 声明权限 > 声明ACL权限 > 向用户申请授权 > 访问接口 |
如果应用需要将自身的APL等级声明为system_basic及以上,在开发应用安装包时,需要修改应用的HarmonyAppProvision配置文件即SDK目录下的“Toolchains / _{Version} _/ lib / UnsgnedReleasedProfileTemplate.json
”文件),并重新进行应用签名。
修改方式:
HarmonyAppProvision配置文件示例如下所示,修改"bundle-info" > “apl” 字段。
"bundle-info" : {
// ...
"apl": "system_basic",
// ...
},
json
说明: 直接修改HarmonyAppProvision配置文件的方式,仅用于应用调试阶段使用,不可用于发布上架应用市场。如果需要开发商用版本的应用,请在对应的应用市场进行发布证书和Profile文件的申请。
3.3、解读
- 应用可以申请的权限,不能大于自身权限(system_core>system_basic>normal),如果越权,要么ACL使能,要么修改自身应用权限等级。
- 所有权限使用第一步都是在配置文件module.json5中声明,如果是user_grant,需要弹窗让用户手动点击授权,具体实现方式在(('4、如何获取应用权限?'))
- 如果修改了应用APL等级((('2.3、解读'))),就不需要ACL使能步骤,参考(('3.2、system_basic等级应用申请权限的方式'))的前两行。
4、如何获取应用权限?
- 权限类型可分为system_grant(系统授权)和user_grant(用户授权),所有权限获取都必须先在配置文件中声明。
4.1、如何获取system_grant权限
- 如果在应用中申请了system_grant权限,那么系统会在用户安装应用时,自动把相应权限授予给应用。
4.2、如何获取user_grant权限
user_grant权限在用户手动允许授权后,应用才会真正获取相应权限,从而成功访问操作目标对象。
首先明确一点, ArkTs应用和Native(C++)应用都是ArkTs写页面逻辑,唯一区别是函数实现是JS还是C++。而对于申请权限,我们可以看成是页面逻辑的一部分,此时申请权限对ArkTs应用和Native(C++)应用是通用的。先给出配置文件申明,再给出具体ets实现。
"requestPermissions": [ //user_grant权限申明方式 { "name": "ohos.permission.GET_DEFAULT_APPLICATION", "reason": "$string:module_desc", "usedScene": { "abilities": [ "UIAbility" ], "when": "inuse" } }, //system_grant权限申明方式1 { "name": "ohos.permission.GET_NETWORK_INFO", "reason": "$string:module_desc", "usedScene": { "abilities": [ "UIAbility" ], "when": "always" } }, //system_grant权限申明方式2,不推荐 { "name": "ohos.permission.GET_NETWORK_INFO", }, ]
import abilityAccessCtrl, { PermissionRequestResult } from '@ohos.abilityAccessCtrl'; import { Permissions } from '@ohos.abilityAccessCtrl'; import bundleManager from '@ohos.bundle.bundleManager'; import common from '@ohos.app.ability.common'; const TAG: string = '[Permission]'; const PERMISSIONS: Array<Permissions> = [ "ohos.permission.MICROPHONE", ]; export default async function grantPermission(context: common.UIAbilityContext): Promise<boolean> { try { // 获取应用程序的accessTokenID let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf( bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION ); let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo; let tokenId = appInfo.accessTokenId; let atManager = abilityAccessCtrl.createAtManager(); let pems: Array<Permissions> = []; for (let i = 0; i < PERMISSIONS.length; i++) { let state = await atManager.checkAccessToken(tokenId, PERMISSIONS[i]); console.info(TAG + `grantPermission checkAccessToken ${PERMISSIONS[i]} + : ${JSON.stringify(state)}`); if (state !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { pems.push(PERMISSIONS[i]); } } if (pems.length > 0) { console.info(TAG + 'grantPermission requestPermissionsFromUser :' + JSON.stringify(pems)); let ctx: common.UIAbilityContext = context; let result: PermissionRequestResult = await atManager.requestPermissionsFromUser(ctx, pems); let grantStatus: Array<number> = result.authResults; let length: number = grantStatus.length; for (let i = 0; i < length; i++) { console.info(TAG + `grantPermission requestPermissionsFromUser ${result.permissions[i]} + : ${grantStatus[i]}`); if (grantStatus[i] === 0) { // 用户授权,可以继续访问目标操作 } else { // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能 console.log(TAG + 'grantPermission fail '); return false; } } } // 授权成功 console.info(TAG + 'grantPermission success '); return true; } catch (e) { console.info(TAG + 'grantPermission fail '); return false; } }
console.log可以换成Hilog,context可以通过createWindow时set全局变量,再使用时get全局变量的方式获取,PERMISSIONS也可以通过传参获取。为了尽量减少额外依赖,换成了上面这个版本。
使用方法如下,在页面初始化时弹窗获取。
import grantPermission from '../utils/PerssionUtils'; import { BusinessError } from '@kit.BasicServicesKit'; import { common } from '@kit.AbilityKit'; @Entry @Component struct Index { async aboutToAppear(): Promise<void> { // 获取权限 await grantPermission(getContext(this) as common.UIAbilityContext).catch((rej: BusinessError) => { console.info('TAG' + `权限申请失败 ${JSON.stringify(rej)}`); }); } build() { Column() { Text('Hello') .fontSize(50) } .justifyContent(FlexAlign.Center) .alignItems(HorizontalAlign.Center) .backgroundColor('#EDF1FC') .height('100%') .width('100%') } }
效果(5.0弹窗默认居中显示,4.1默认底部显示)
5、应用权限列表及使用方法
应用权限列表查询网址(对所有应用开发,normal等级):https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/security/AccessToken/permissions-for-all.md
应用权限列表查询网址(对系统应用开放,system_basic.system_core等级)https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/security/AccessToken/permissions-for-system-apps.md
5.1、public-sdk下normal权限user_grant授权
假设我们的应用需要使用分布式能力的查询可信设备列表接口,可以看到标明需要ohos.permission.DISTRIBUTED_DATASYNC权限。
然后我们根据权限名去那两个网址查询,可以看到为normal权限,普通应用可以用。授权方式是user_grant,需要弹窗让用户确认。
修改配置文件module.json5。然后使用(('4.2、如何获取user_grant权限'))的grantPermission函数进行弹窗授权。
"requestPermissions": [ //user_grant权限申明方式 { "name": "ohos.permission.DISTRIBUTED_DATASYNC", "reason": "$string:module_desc", "usedScene": { "abilities": [ "UIAbility" ], "when": "inuse" } }, ]
用户点击允许,就可以开始调用getAvailableDeviceListSync。否则会报权限相关错误。
import { distributedDeviceManager } from '@kit.DistributedServiceKit'; import { BusinessError } from '@kit.BasicServicesKit'; try { let deviceInfoList: Array<distributedDeviceManager.DeviceBasicInfo> = dmInstance.getAvailableDeviceListSync(); } catch (err) { let e: BusinessError = err as BusinessError; console.error('getAvailableDeviceListSync errCode:' + e.code + ',errMessage:' + e.message); }
5.2、fullsdk下system_basic权限system_grant授权
假设我们的应用需要使用分布式回复用户UI的操作,可以看到标明需要ohos.permission.ACCESS_SERVICE_DM权限,同时也是系统接口。
- 对于系统接口,需要使用full_sdk,可以看我的另一篇文章应用开发基础之fullsdk使用。
- 对于权限ohos.permission.ACCESS_SERVICE_DM,我们直接去上面两个网址查询。
可以看到为system_basic权限,普通应用不可以用。授权方式是system_grant。此处我们选择修改应用APL等级。直接修改配置文件就可以使用
参考(('2.3、解读'))修改应用APL等级为system_core,然后修改配置文件module.json5。
"requestPermissions": [ //system_grant权限申明方式 { "name": "ohos.permission.GET_DEFAULT_APPLICATION", "reason": "$string:module_desc", "usedScene": { "abilities": [ "UIAbility" ], "when": "always" } }, ]
至此就可以开始使用权限对应的接口。
import { BusinessError } from '@kit.BasicServicesKit'; try { /* action = 0 - 允许授权 action = 1 - 取消授权 action = 2 - 授权框用户操作超时 action = 3 - 取消pin码框展示 action = 4 - 取消pin码输入框展示 action = 5 - pin码输入框确定操作 */ let operation = 0; dmInstance.replyUiAction(operation, 'extra'); } catch (err) { let e: BusinessError = err as BusinessError; console.error('replyUiAction errCode:' + e.code + ',errMessage:' + e.message); }
6、结语
应该会更新文档,有问题可以先提,到时候统一改。
参考链接
更多推荐
所有评论(0)