• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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应用需要在项目的配置文件中逐个声明所需的权限,否则应用将无法获取授权。
17
18> **说明**:
19>
20> 应用在申请`system_basic`和`system_core`等级权限时,需要提升权限等级,因为应用默认的权限等级为`normal`。如果应用需要申请高于默认等级的权限,除了在配置文件中进行声明之外,还需要通过[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`等级。如果应用需要截取屏幕图像,则需要申请`ohos.permission.CAPTURE_SCREEN`权限,该权限属于`system_core`等级。此时,需要将相关权限项配置到[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![](figures/permission-read_calendar.png)
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(`Failed to get bundle info for self. 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(`Failed to check access token. 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(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
218
219       // ...
220     }
221   }
222   ```
223
224   在UI中向用户申请授权。
225   ```typescript
226   import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
227   import common from '@ohos.app.ability.common';
228
229   const permissions: Array<Permissions> = ['ohos.permission.READ_CALENDAR'];
230
231   @Entry
232   @Component
233   struct Index {
234     reqPermissionsFromUser(permissions: Array<Permissions>): void {
235       let context = getContext(this) as common.UIAbilityContext;
236       let atManager = abilityAccessCtrl.createAtManager();
237       // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
238       atManager.requestPermissionsFromUser(context, permissions).then((data) => {
239         let grantStatus: Array<number> = data.authResults;
240         let length: number = grantStatus.length;
241         for (let i = 0; i < length; i++) {
242           if (grantStatus[i] === 0) {
243             // 用户授权,可以继续访问目标操作
244           } else {
245             // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
246             return;
247           }
248         }
249         // 授权成功
250       }).catch((err) => {
251         console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
252       })
253     }
254
255     // 页面展示
256     build() {
257       // ...
258     }
259   }
260   ```
261
2624. 处理授权结果。
263
264   调用[requestPermissionsFromUser()](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)方法后,应用程序将等待用户授权的结果。如果用户授权,则可以继续访问目标操作。如果用户拒绝授权,则需要提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限。
265
266   ```ts
267   function openPermissionsInSystemSettings(): void {
268     let context = getContext(this) as common.UIAbilityContext;
269     let wantInfo = {
270       action: 'action.settings.app.info',
271       parameters: {
272         settingsParamBundleName: 'com.example.myapplication' // 打开指定应用的详情页面
273       }
274     }
275     context.startAbility(wantInfo).then(() => {
276       // ...
277     }).catch((err) => {
278       // ...
279     })
280   }
281   ```
282
283### FA模型
284
285通过调用[requestPermissionsFromUser()](../reference/apis/js-apis-inner-app-context.md#contextrequestpermissionsfromuser7)接口向用户动态申请授权。
286
287```js
288import featureAbility from '@ohos.ability.featureAbility';
289
290reqPermissions() {
291    let context = featureAbility.getContext();
292    let array:Array<string> = ["ohos.permission.PERMISSION2"];
293    //requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
294    context.requestPermissionsFromUser(array, 1).then(function(data) {
295        console.log("data:" + JSON.stringify(data));
296        console.log("data permissions:" + JSON.stringify(data.permissions));
297        console.log("data result:" + JSON.stringify(data.authResults));
298    }, (err) => {
299        console.error('Failed to start ability', err.code);
300    });
301}
302```
303## user_grant权限预授权
304应用在申请`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`。
305
306- `bundleName`字段配置为应用的Bundle名称。
307- `app_signature`字段配置为应用的指纹信息。指纹信息的配置参见[应用特权配置指南](../../device-dev/subsystems/subsys-app-privilege-config-guide.md#install_list_capabilityjson中配置)。
308- `permissions`字段中`name`配置为需要预授权的`user_grant`类型的权限名;`permissions`字段中`userCancellable`表示为用户是否能够取消该预授权,配置为true,表示支持用户取消授权,为false则表示不支持用户取消授权。
309
310> **说明**:当前仅支持预置应用配置该文件。
311
312```json
313[
314  // ...
315  {
316    "bundleName": "com.example.myapplication", // Bundle名称
317    "app_signature": ["****"], // 指纹信息
318    "permissions":[
319      {
320        "name": "ohos.permission.PERMISSION_X", // user_grant类型预授权的权限名
321        "userCancellable": false // 用户不可取消授权
322      },
323      {
324        "name": "ohos.permission.PERMISSION_Y", // user_grant类型预授权的权限名
325        "userCancellable": true // 用户可取消授权
326      }
327    ]
328  }
329]
330```
331
332## 相关实例
333
334针对访问控制,有以下相关实例可供参考:
335
336- [为应用添加运行时权限(ArkTS)(Full SDK)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Ability/AccessPermission)