1# 访问控制授权申请 2 3## 场景介绍 4 5[应用的APL(Ability Privilege Level)等级](accesstoken-overview.md#应用apl等级说明)分为`normal`、`system_basic`和`system_core`三个等级,默认情况下,应用的APL等级都为`normal`等级。[权限类型](accesstoken-overview.md#权限类型说明)分为`system_grant`和`user_grant`两种类型。应用可申请的权限项参见[应用权限列表](permission-list.md)。 6 7本文将从如下场景分别介绍: 8 9- [配置文件权限声明](#配置文件权限声明) 10- [ACL方式声明](#acl方式声明) 11- [向用户申请授权](#向用户申请授权) 12- [user_grant权限预授权](#user_grant权限预授权) 13 14## 配置文件权限声明 15 16应用需要在工程配置文件中,对需要的权限逐个声明,未在配置文件中声明的权限,应用将无法获得授权。OpenHarmony提供了两种应用模型,分别为FA模型和Stage模型,更多信息可以参考[应用模型解读](../application-models/application-model-description.md)。不同的应用模型的应用包结构不同,所使用的配置文件不同。 17 18> **说明**: 19> 20> 应用默认的APL等级为`normal`,当应用需要申请`system_basic`和`system_core`等级时,除了在配置文件中进行权限声明之外,还需要通过[ACL方式](#acl方式声明)进行声明使用。 21 22配置文件标签说明如下表所示。 23 24| 标签 | 是否必填 | 说明 | 25| --------- | -------- | ------------------------------------------------------------ | 26| name | 是 | 权限名称。 | 27| reason | 否 | 描述申请权限的原因。<br />> **说明**:当申请的权限为user_grant权限时,此字段必填。 | 28| usedScene | 否 | 描述权限使用的场景和时机。<br />> **说明**:当申请的权限为user_grant权限时,此字段必填。 | 29| abilities | 否 | 标识需要使用到该权限的Ability,标签为数组形式。<br/>**适用模型**:Stage模型 | 30| ability | 否 | 标识需要使用到该权限的Ability,标签为数组形式。<br/>**适用模型**:FA模型 | 31| when | 否 | 标识权限使用的时机,值为`inuse/always`。<br />- inuse:表示为仅允许前台使用。<br />- always:表示前后台都可使用。 | 32 33### Stage模型 34 35使用Stage模型的应用,需要在[module.json5配置文件](../quick-start/module-configuration-file.md)中声明权限。 36 37```json 38{ 39 "module" : { 40 // ... 41 "requestPermissions":[ 42 { 43 "name" : "ohos.permission.PERMISSION1", 44 "reason": "$string:reason", 45 "usedScene": { 46 "abilities": [ 47 "FormAbility" 48 ], 49 "when":"inuse" 50 } 51 }, 52 { 53 "name" : "ohos.permission.PERMISSION2", 54 "reason": "$string:reason", 55 "usedScene": { 56 "abilities": [ 57 "FormAbility" 58 ], 59 "when":"always" 60 } 61 } 62 ] 63 } 64} 65``` 66 67### FA模型 68 69使用FA模型的应用,需要在config.json配置文件中声明权限。 70 71```json 72{ 73 "module" : { 74 // ... 75 "reqPermissions":[ 76 { 77 "name" : "ohos.permission.PERMISSION1", 78 "reason": "$string:reason", 79 "usedScene": { 80 "ability": [ 81 "FormAbility" 82 ], 83 "when":"inuse" 84 } 85 }, 86 { 87 "name" : "ohos.permission.PERMISSION2", 88 "reason": "$string:reason", 89 "usedScene": { 90 "ability": [ 91 "FormAbility" 92 ], 93 "when":"always" 94 } 95 } 96 ] 97 } 98} 99``` 100 101## ACL方式声明 102 103应用在申请`system_basic`和`system_core`等级权限时,高于应用默认的`normal`等级。当应用需要申请权限项的等级高于应用默认的等级时,需要通过ACL方式进行声明使用。 104 105例如应用在申请访问用户公共目录下音乐类型的文件,需要申请` ohos.permission.WRITE_AUDIO`权限,该权限为`system_basic`等级;以及应用在申请截取屏幕图像功能,该权限为`system_core`等级,需要申请` ohos.permission.CAPTURE_SCREEN`权限。此时需要将相关权限项配置到[HarmonyAppProvision配置文件](app-provision-structure.md)的`acl`字段中。 106 107```json 108{ 109 // ... 110 "acls":{ 111 "allowed-acls":[ 112 "ohos.permission.WRITE_AUDIO", 113 "ohos.permission.CAPTURE_SCREEN" 114 ] 115 } 116} 117``` 118 119## 向用户申请授权 120 121当应用需要访问用户的隐私信息或使用系统能力时,例如获取位置信息、访问日历、使用相机拍摄照片或录制视频等,应该向用户请求授权。这需要使用 `user_grant` 类型权限。在此之前,应用需要进行权限校验,以判断当前调用者是否具备所需的权限。如果权限校验结果表明当前应用尚未被授权该权限,则应使用动态弹框授权方式,为用户提供手动授权的入口。示意效果如下图所示。 122 123图1 向用户申请授权 124 125 126> **说明**: 127> 128> 每次访问受目标权限保护的接口之前,都需要使用 [requestPermissionsFromUser()](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9) 接口请求相应的权限。用户可能在动态授予权限后通过系统设置来取消应用的权限,因此不能将之前授予的授权状态持久化。 129 130### Stage模型 131 132以允许应用读取日历信息为例进行说明。 133 1341. 申请`ohos.permission.READ_CALENDAR`权限,配置方式请参见[访问控制授权申请](#配置文件权限声明)。 135 1362. 校验当前是否已经授权。 137 138 在进行权限申请之前,需要先检查当前应用程序是否已经被授予了权限。可以通过调用[checkAccessToken()](../reference/apis/js-apis-abilityAccessCtrl.md#checkaccesstoken9)方法来校验当前是否已经授权。如果已经授权,则可以直接访问目标操作,否则需要进行下一步操作,即向用户申请授权。 139 140 ```ts 141 import bundleManager from '@ohos.bundle.bundleManager'; 142 import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; 143 144 async function checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> { 145 let atManager = abilityAccessCtrl.createAtManager(); 146 let grantStatus: abilityAccessCtrl.GrantStatus; 147 148 // 获取应用程序的accessTokenID 149 let tokenId: number; 150 try { 151 let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); 152 let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo; 153 tokenId = appInfo.accessTokenId; 154 } catch (err) { 155 console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`); 156 } 157 158 // 校验应用是否被授予权限 159 try { 160 grantStatus = await atManager.checkAccessToken(tokenId, permission); 161 } catch (err) { 162 console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`); 163 } 164 165 return grantStatus; 166 } 167 168 async function checkPermissions(): Promise<void> { 169 const permissions: Array<Permissions> = ['ohos.permission.READ_CALENDAR']; 170 let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(permissions[0]); 171 172 if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { 173 // 已经授权,可以继续访问目标操作 174 } else { 175 // 申请日历权限 176 } 177 } 178 ``` 179 1803. 动态向用户申请授权。 181 182 动态向用户申请权限是指在应用程序运行时向用户请求授权的过程。可以通过调用[requestPermissionsFromUser()](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)方法来实现。该方法接收一个权限列表参数,例如位置、日历、相机、麦克风等。用户可以选择授予权限或者拒绝授权。 183 184 可以在UIAbility的`onWindowStageCreate()`回调中调用[requestPermissionsFromUser()](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)方法来动态申请权限,也可以根据业务需要在UI中向用户申请授权。 185 186 在UIAbility中向用户申请授权。 187 188 ```typescript 189 import UIAbility from '@ohos.app.ability.UIAbility'; 190 import window from '@ohos.window'; 191 import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; 192 193 const permissions: Array<Permissions> = ['ohos.permission.READ_CALENDAR']; 194 195 export default class EntryAbility extends UIAbility { 196 // ... 197 198 onWindowStageCreate(windowStage: window.WindowStage) { 199 // Main window is created, set main page for this ability 200 let context = this.context; 201 let atManager = abilityAccessCtrl.createAtManager(); 202 // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 203 204 atManager.requestPermissionsFromUser(context, permissions).then((data) => { 205 let grantStatus: Array<number> = data.authResults; 206 let length: number = grantStatus.length; 207 for (let i = 0; i < length; i++) { 208 if (grantStatus[i] === 0) { 209 // 用户授权,可以继续访问目标操作 210 } else { 211 // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限 212 return; 213 } 214 } 215 // 授权成功 216 }).catch((err) => { 217 console.error(`requestPermissionsFromUser failed, code is ${err.code}, message is ${err.message}`); 218 }) 219 220 // ... 221 } 222 } 223 ``` 224 225 在UI中向用户申请授权。 226 ```typescript 227 import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; 228 import common from '@ohos.app.ability.common'; 229 230 const permissions: Array<Permissions> = ['ohos.permission.READ_CALENDAR']; 231 232 @Entry 233 @Component 234 struct Index { 235 reqPermissionsFromUser(permissions: Array<Permissions>): void { 236 let context = getContext(this) as common.UIAbilityContext; 237 let atManager = abilityAccessCtrl.createAtManager(); 238 // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 239 atManager.requestPermissionsFromUser(context, permissions).then((data) => { 240 let grantStatus: Array<number> = data.authResults; 241 let length: number = grantStatus.length; 242 for (let i = 0; i < length; i++) { 243 if (grantStatus[i] === 0) { 244 // 用户授权,可以继续访问目标操作 245 } else { 246 // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限 247 return; 248 } 249 } 250 // 授权成功 251 }).catch((err) => { 252 console.error(`requestPermissionsFromUser failed, code is ${err.code}, message is ${err.message}`); 253 }) 254 } 255 256 // 页面展示 257 build() { 258 // ... 259 } 260 } 261 ``` 262 2634. 处理授权结果。 264 265 调用[requestPermissionsFromUser()](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)方法后,应用程序将等待用户授权的结果。如果用户授权,则可以继续访问目标操作。如果用户拒绝授权,则需要提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限。 266 267 ```ts 268 function openPermissionsInSystemSettings(): void { 269 let context = getContext(this) as common.UIAbilityContext; 270 let wantInfo = { 271 action: 'action.settings.app.info', 272 parameters: { 273 settingsParamBundleName: 'com.example.myapplication' // 打开指定应用的详情页面 274 } 275 } 276 context.startAbility(wantInfo).then(() => { 277 // ... 278 }).catch((err) => { 279 // ... 280 }) 281 } 282 ``` 283 284### FA模型 285 286通过调用[requestPermissionsFromUser()](../reference/apis/js-apis-inner-app-context.md#contextrequestpermissionsfromuser7)接口向用户动态申请授权。 287 288```js 289import featureAbility from '@ohos.ability.featureAbility'; 290 291reqPermissions() { 292 let context = featureAbility.getContext(); 293 let array:Array<string> = ["ohos.permission.PERMISSION2"]; 294 //requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 295 context.requestPermissionsFromUser(array, 1).then(function(data) { 296 console.log("data:" + JSON.stringify(data)); 297 console.log("data permissions:" + JSON.stringify(data.permissions)); 298 console.log("data result:" + JSON.stringify(data.authResults)); 299 }, (err) => { 300 console.error('Failed to start ability', err.code); 301 }); 302} 303``` 304## user_grant权限预授权 305应用在申请`user_grant`类型的权限默认未授权,需要通过拉起弹框由用户确认是否授予该权限。对于一些预制应用,不希望出现弹窗申请`user_grant`类型的权限,例如系统相机应用需要使用麦克风` ohos.permission.MICROPHONE`等权限,需要对麦克风等权限进行预授权,可以通过预授权的方式完成`user_grant`类型权限的授权。[预置配置文件](https://gitee.com/openharmony/vendor_hihope/blob/master/rk3568/preinstall-config/install_list_permissions.json)在设备上的路径为`/system/etc/app/install_list_permission.json`,设备开机启动时会读取该配置文件,在应用安装会对在文件中配置的`user_grant`类型权限授权。预授权配置文件字段内容包括`bundleName`、`app_signature`和`permissions`。 306 307- `bundleName`字段配置为应用的Bundle名称。 308- `app_signature`字段配置为应用的指纹信息。指纹信息的配置参见[应用特权配置指南](../../device-dev/subsystems/subsys-app-privilege-config-guide.md#install_list_capabilityjson中配置)。 309- `permissions`字段中`name`配置为需要预授权的`user_grant`类型的权限名;`permissions`字段中`userCancellable`表示为用户是否能够取消该预授权,配置为true,表示支持用户取消授权,为false则表示不支持用户取消授权。 310 311> **说明**:当前仅支持预置应用配置该文件。 312 313```json 314[ 315 // ... 316 { 317 "bundleName": "com.example.myapplication", // Bundle名称 318 "app_signature": ["****"], // 指纹信息 319 "permissions":[ 320 { 321 "name": "ohos.permission.PERMISSION_X", // user_grant类型预授权的权限名 322 "userCancellable": false // 用户不可取消授权 323 }, 324 { 325 "name": "ohos.permission.PERMISSION_Y", // user_grant类型预授权的权限名 326 "userCancellable": true // 用户可取消授权 327 } 328 ] 329 } 330] 331``` 332 333## 相关实例 334 335针对访问控制,有以下相关实例可供参考: 336 337- [为应用添加运行时权限(ArkTS)(Full SDK)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Ability/AccessPermission)