TokenID

系統采用TokenID(Token identity)作為應用的唯一標識。權限管理服務通過應用的TokenID來管理應用的AT(Access Token)信息,包括應用身份標識APP ID、子用戶ID、應用分身索引信息、應用APL、應用權限授權狀態等。在資源使用時,系統將通過TokenID作為唯一身份標識映射獲取對應應用的權限授權狀態信息,并依此進行鑒權,從而管控應用的資源訪問行為。

值得注意的是,系統支持多用戶特性和應用分身特性,同一個應用在不同的子用戶下和不同的應用分身下會有各自的AT,這些AT的TokenID也是不同的。

授權方式

根據授權方式的不同,權限類型可分為system_grant(系統授權)和user_grant(用戶授權)。

  1. 如果在應用中申請了system_grant權限,那么系統會在用戶安裝應用時,自動把相應權限授予給應用。
  2. user_grant權限不僅需要在安裝包中申請權限,還需要在應用動態運行時,通過發送彈窗的方式請求用戶授權。在用戶手動允許授權后,應用才會真正獲取相應權限,從而成功訪問操作目標對象。

system_grant權限

ohos.permission.INTERNET
允許使用Internet網絡。

ohos.permission.USE_BLUETOOTH
允許應用查看藍牙的配置。

ohos.permission.GET_BUNDLE_INFO
允許查詢應用的基本信息。

ohos.permission.PREPARE_APP_TERMINATE
允許應用關閉前執行自定義的預關閉動作。

ohos.permission.PRINT 
允許應用獲取打印框架的能力。

ohos.permission.DISCOVER_BLUETOOTH
允許應用配置本地藍牙,查找遠端設備且與之配對連接。

ohos.permission.ACCELEROMETER
允許應用讀取加速度傳感器的數據。

ohos.permission.ACCESS_BIOMETRIC
允許應用使用生物特征識別能力進行身份認證。

ohos.permission.ACCESS_NOTIFICATION_POLICY
在本設備上允許應用訪問通知策略。

ohos.permission.GET_NETWORK_INFO
允許應用獲取數據網絡信息。

ohos.permission.GET_WIFI_INFO
允許應用獲取Wi-Fi信息。

ohos.permission.GYROSCOPE
允許應用讀取陀螺儀傳感器的數據。

ohos.permission.KEEP_BACKGROUND_RUNNING
允許Service Ability在后臺持續運行。

ohos.permission.NFC_CARD_EMULATION
允許應用實現卡模擬功能。

ohos.permission.NFC_TAG
允許應用讀寫Tag卡片。

ohos.permission.PRIVACY_WINDOW
允許應用將窗口設置為隱私窗口,禁止截屏錄屏

ohos.permission.PUBLISH_AGENT_REMINDER
允許該應用使用后臺代理提醒。

ohos.permission.SET_NETWORK_INFO
允許應用配置數據網絡。

ohos.permission.SET_WIFI_INFO
允許應用配置Wi-Fi設備。

ohos.permission.VIBRATE
允許應用控制馬達振動。

ohos.permission.CLEAN_BACKGROUND_PROCESSES
允許應用根據包名清理相關后臺進程。

ohos.permission.COMMONEVENT_STICKY
允許應用發布粘性公共事件。

ohos.permission.MODIFY_AUDIO_SETTINGS
允許應用修改音頻設置。

ohos.permission.RUNNING_LOCK
允許應用獲取運行鎖,保證應用在后臺的持續運行。

ohos.permission.SET_WALLPAPER**
允許應用設置壁紙。

ohos.permission.ACCESS_CERT_MANAGER
允許應用進行查詢證書及私有憑據等操作。

ohos.permission.hsdr.HSDR_ACCESS
允許應用訪問安全檢測與響應框架。

user_grant權限

ohos.permission.CAMERA
允許應用使用相機。

ohos.permission.READ_MEDIA
允許應用讀取用戶外部存儲中的媒體文件信息。

ohos.permission.WRITE_MEDIA
允許應用讀寫用戶外部存儲中的媒體文件信息。

ohos.permission.APPROXIMATELY_LOCATION
允許應用獲取設備模糊位置信息。
ohos.permission.LOCATION
允許應用獲取設備位置信息。

ohos.permission.MICROPHONE
允許應用使用麥克風。

ohos.permission.READ_CALENDAR
允許應用讀取日歷信息。

ohos.permission.READ_HEALTH_DATA
允許應用讀取用戶的健康數據。

ohos.permission.WRITE_CALENDAR
允許應用添加、移除或更改日歷活動。

ohos.permission.ACCESS_BLUETOOTH
允許應用接入藍牙并使用藍牙能力,例如配對、連接外圍設備等。

ohos.permission.MEDIA_LOCATION
允許應用訪問用戶媒體文件中的地理位置信息。

ohos.permission.APP_TRACKING_CONSENT
允許應用讀取開放匿名設備標識符。

ohos.permission.ACTIVITY_MOTION
允許應用讀取用戶的運動狀態。

ohos.permission.DISTRIBUTED_DATASYNC
允許不同設備間的數據交換。

聲明權限

應用在申請權限時,需要在項目的配置文件中,逐個聲明需要的權限,否則應用將無法獲取授權。

應用需要在module.json5配置文件的requestPermissions標簽中聲明權限。

屬性 說明 取值范圍
name 必須,填寫需要使用的權限名稱。 需為系統已定義的權限
reason 可選,當申請的權限為user_grant權限時此字段必填,用于描述申請權限的原因。說明:該字段用于應用上架校驗,當申請的權限為user_grant權限時必填,并且需要進行多語種適配。 使用string類資源引用。格式為$string: ***
usedScene 可選,當申請的權限為user_grant權限時此字段必填。描述權限使用的場景由abilities和when組成。其中abilities可以配置為多個UIAbility組件,when表示調用時機。說明:默認為可選,當申請的權限為user_grant權限時,abilities標簽必填,when標簽可選。 abilities:UIAbility或者ExtensionAbility組件的名稱。when:inuse(使用時)、always(始終)。
{
  "module" : {
    // ...
    "requestPermissions":[
      {
        "name" : "ohos.permission.PERMISSION1",
        "reason": "$string:reason",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when":"inuse"
        }
      },
      {
        "name" : "ohos.permission.PERMISSION2",
        "reason": "$string:reason",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when":"always"
        }
      }
    ]
  }
}

權限使用理由的文案內容規范

  1. 保持句子簡潔、不要加入多余的分割符號。

    建議句式:用于某事。

    示例:用于掃碼拍照。

  2. 用途描述的字串建議小于72個字符(即36個中文字符,UI界面顯示大約為兩行)。不能超過256個字符,以保證多語言適配的體驗。

  3. 如果不寫,將展示默認的申請理由。

向用戶申請授權

當應用需要訪問用戶的隱私信息或使用系統能力時,例如獲取位置信息、訪問日歷、使用相機拍攝照片或錄制視頻等,應該向用戶請求授權,這部分權限是user_grant權限。

申請user_grant權限步驟

  1. 在配置文件中,聲明應用需要請求的權限。

  2. 將應用中需要申請權限的目標對象與對應目標權限進行關聯,讓用戶明確地知道,哪些操作需要用戶向應用授予指定的權限。

  3. 運行應用時,在用戶觸發訪問操作目標對象時應該調用接口,精準觸發動態授權彈框。該接口的內部會檢查當前用戶是否已經授權應用所需的權限,如果當前用戶尚未授予應用所需的權限,該接口會拉起動態授權彈框,向用戶請求授權。

  4. 檢查用戶的授權結果,確認用戶已授權才可以進行下一步操作。

約束與限制

  • 每次執行需要目標權限的操作時,應用都必須檢查自己是否已經具有該權限。

    如需檢查用戶是否已向您的應用授予特定權限,可以使用checkAccessToken()函數,此方法會返回PERMISSION_GRANTEDPERMISSION_DENIED

  • 每次訪問受目標權限保護的接口之前,都需要使用requestPermissionsFromUser()接口請求相應的權限。

    用戶可能在動態授予權限后通過系統設置來取消應用的權限,因此不能將之前授予的授權狀態持久化。

  • user_grant權限授權要基于用戶可知可控的原則,需要應用在運行時主動調用系統動態申請權限的接口,系統彈框由用戶授權,用戶結合應用運行場景的上下文,識別出應用申請相應敏感權限的合理性,從而做出正確的選擇。

  • 系統不鼓勵頻繁彈窗打擾用戶,如果用戶拒絕授權,將無法再次拉起彈窗。需要應用引導用戶在系統應用“設置”的界面中手動授予權限。

1、檢查單個權限是否授權

/**
 * 校驗當前權限是否已經授權
 * @param permission
 * @returns
 */
async checkAccessToken(permission: Permissions) {
  let atManager = abilityAccessCtrl.createAtManager();
  let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;

  // 獲取應用程序的accessTokenID
  let tokenID: number = 0;
  try {
    let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
    let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
    tokenID = appInfo.accessTokenId;
  } catch (err) {
    console.error(`getBundleInfoForSelf failed, error: ${err}`);
  }

  // 校驗應用是否被授予權限
  try {
    grantStatus = await atManager.checkAccessToken(tokenID, permission);
  } catch (err) {
    console.error(`checkAccessToken failed, error: ${err}`);
  }
  return grantStatus;
}

2、批量檢查權限

/**
 * 請求權限
 * @param permissions
 * @param context
 */
requestPermissions(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  // requestPermissionsFromUser會判斷權限的授權狀態來決定是否喚起彈窗
  atManager.requestPermissionsFromUser(context, permissions).then((data) => {
    let grantStatus: Array<number> = data.authResults;
    let length: number = grantStatus.length;
    for (let i = 0; i < length; i++) {
      if (grantStatus[i] === 0) {
        // 用戶授權,可以繼續訪問目標操作

      } else {
        // 用戶拒絕授權,提示用戶必須授權才能訪問當前頁面的功能,并引導用戶到系統設置中打開相應的權限
        return;
      }
    }
    // 授權成功
  }).catch((err: BusinessError) => {
    console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
  })
}

3、批量申請權限

/**
 * 這里傳入需要檢查的權限,也可以傳入權限數組Array<Permissions>
 * @param permission
 * @returns
 */
async checkAndRequestPermissions(permissions: Array<Permissions>, context: common.UIAbilityContext): Promise<void> {
  for (let i = 0; i < permissions.length; i++) {
    let grantStatus: abilityAccessCtrl.GrantStatus = await this.checkAccessToken(permissions[i]);
    if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      // 已經授權,可以繼續訪問目標操作

    } else {
      // 申請權限
      this.requestPermissions(this.permissions, context)
    }
  }

}

4、申請權限的使用方法


aboutToAppear(): void {
  const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext
  this.checkAndRequestPermissions(this.permissions, context)
}