#跟着坚果学鸿蒙# HarmonyOS 5 DataAbility权限控制详解与实践
·
一、DataAbility权限控制概述
在HarmonyOS 5应用开发中,DataAbility作为数据服务提供者,其权限控制机制是保障数据安全的关键环节。DataAbility的权限控制分为静态权限控制和动态权限控制两部分,通过精细化的权限管理,确保只有经过授权的Ability才能访问特定数据。
1.1 静态权限控制
静态权限控制通过在config.json配置文件中声明权限来实现,主要包含三个配置项:
readPermission
:读取数据所需的权限writePermission
:写入数据所需的权限Permission
:通用权限(读写都需要)
当DataAbility被拉起时,系统会根据这些配置进行权限校验。如果调用方不具备相应权限,则访问会被拒绝。
1.2 动态权限控制
动态权限控制则是在运行时通过代码检查调用方权限,适用于更复杂的权限场景。开发者可以在DataAbility的业务逻辑中,动态判断调用方是否具有特定权限。
二、DataAbility权限配置实践
下面我们通过一个完整的联系人管理DataAbility示例,演示如何在HarmonyOS 5中实现DataAbility权限控制。
2.1 配置静态权限
首先在module.json5
中声明DataAbility并配置权限:
{
"module": {
"abilities": [
{
"name": "ContactDataAbility",
"type": "data",
"uri": "dataability://com.example.contactprovider",
"readPermission": "ohos.permission.READ_CONTACTS",
"writePermission": "ohos.permission.WRITE_CONTACTS",
"exported": true
}
],
"requestPermissions": [
{
"name": "ohos.permission.READ_CONTACTS",
"reason": "读取联系人信息",
"usedScene": {
"abilities": ["ContactDataAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.WRITE_CONTACTS",
"reason": "修改联系人信息",
"usedScene": {
"abilities": ["ContactDataAbility"],
"when": "inuse"
}
}
]
}
}
2.2 实现DataAbility
创建一个完整的联系人DataAbility实现类:
import dataAbility from '@ohos.data.dataAbility';
import relationalStore from '@ohos.data.relationalStore';
import featureAbility from '@ohos.ability.featureAbility';
const DB_NAME = 'contact_db';
const TABLE_NAME = 'contact';
const DB_VERSION = 1;
let rdbStore: relationalStore.RdbStore;
export default class ContactDataAbility extends dataAbility.DataAbility {
async onInit(want) {
console.info('ContactDataAbility onInit');
try {
const context = featureAbility.getContext();
const config = {
name: DB_NAME,
securityLevel: relationalStore.SecurityLevel.S1
};
// 创建或打开数据库
rdbStore = await relationalStore.getRdbStore(context, config);
// 创建联系人表
const sqlCreateTable = `CREATE TABLE IF NOT EXISTS ${TABLE_NAME}
(id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
phone TEXT,
email TEXT)`;
await rdbStore.executeSql(sqlCreateTable);
return true;
} catch (err) {
console.error(`Failed to init ContactDataAbility, code is ${err.code}, message is ${err.message}`);
return false;
}
}
// 插入联系人
async insert(uri, valueBucket) {
console.info('ContactDataAbility insert');
// 动态权限检查
try {
const callerTokenId = this.context.verifyCallingPermission('ohos.permission.WRITE_CONTACTS');
if (callerTokenId < 0) {
throw new Error('Permission denied: WRITE_CONTACTS required');
}
} catch (err) {
console.error(`Permission check failed: ${err.message}`);
throw err;
}
try {
const insertResult = await rdbStore.insert(TABLE_NAME, valueBucket);
return insertResult;
} catch (err) {
console.error(`Insert failed: ${err.message}`);
throw err;
}
}
// 查询联系人
async query(uri, columns, predicates) {
console.info('ContactDataAbility query');
// 动态权限检查
try {
const callerTokenId = this.context.verifyCallingPermission('ohos.permission.READ_CONTACTS');
if (callerTokenId < 0) {
throw new Error('Permission denied: READ_CONTACTS required');
}
} catch (err) {
console.error(`Permission check failed: ${err.message}`);
throw err;
}
try {
const predicates = new relationalStore.RdbPredicates(TABLE_NAME);
const resultSet = await rdbStore.query(predicates, columns);
return resultSet;
} catch (err) {
console.error(`Query failed: ${err.message}`);
throw err;
}
}
// 更新联系人
async update(uri, valueBucket, predicates) {
console.info('ContactDataAbility update');
// 动态权限检查
try {
const callerTokenId = this.context.verifyCallingPermission('ohos.permission.WRITE_CONTACTS');
if (callerTokenId < 0) {
throw new Error('Permission denied: WRITE_CONTACTS required');
}
} catch (err) {
console.error(`Permission check failed: ${err.message}`);
throw err;
}
try {
const predicates = new relationalStore.RdbPredicates(TABLE_NAME);
const rowsUpdated = await rdbStore.update(valueBucket, predicates);
return rowsUpdated;
} catch (err) {
console.error(`Update failed: ${err.message}`);
throw err;
}
}
// 删除联系人
async delete(uri, predicates) {
console.info('ContactDataAbility delete');
// 动态权限检查
try {
const callerTokenId = this.context.verifyCallingPermission('ohos.permission.WRITE_CONTACTS');
if (callerTokenId < 0) {
throw new Error('Permission denied: WRITE_CONTACTS required');
}
} catch (err) {
console.error(`Permission check failed: ${err.message}`);
throw err;
}
try {
const predicates = new relationalStore.RdbPredicates(TABLE_NAME);
const rowsDeleted = await rdbStore.delete(predicates);
return rowsDeleted;
} catch (err) {
console.error(`Delete failed: ${err.message}`);
throw err;
}
}
}
2.3 调用DataAbility的UI实现
创建一个调用DataAbility的UI页面,演示如何申请权限并使用DataAbility:
@Entry
@Component
struct ContactList {
@State contacts: Array<{id: number, name: string, phone: string}> = []
// 获取联系人列表
async getContacts() {
try {
// 检查权限
const permissions = ['ohos.permission.READ_CONTACTS']
const result = await abilityAccessCtrl.requestPermissionsFromUser(permissions)
if (result.authResults[0] === 0) {
const uri = 'dataability://com.example.contactprovider/contact'
const dataAbilityHelper = dataAbility.createDataAbilityHelper(this.context)
const resultSet = await dataAbilityHelper.query(uri, ['id', 'name', 'phone'], null)
this.contacts = []
while (resultSet.goToNextRow()) {
this.contacts.push({
id: resultSet.getLong(resultSet.getColumnIndex('id')),
name: resultSet.getString(resultSet.getColumnIndex('name')),
phone: resultSet.getString(resultSet.getColumnIndex('phone'))
})
}
resultSet.close()
} else {
prompt.showToast({message: '需要联系人读取权限'})
}
} catch (err) {
prompt.showToast({message: `获取联系人失败: ${err.message}`})
}
}
// 添加联系人
async addContact() {
try {
// 检查权限
const permissions = ['ohos.permission.WRITE_CONTACTS']
const result = await abilityAccessCtrl.requestPermissionsFromUser(permissions)
if (result.authResults[0] === 0) {
const uri = 'dataability://com.example.contactprovider/contact'
const dataAbilityHelper = dataAbility.createDataAbilityHelper(this.context)
const values = {
'name': '新联系人',
'phone': '13800138000',
'email': 'new@example.com'
}
await dataAbilityHelper.insert(uri, values)
this.getContacts()
prompt.showToast({message: '添加成功'})
} else {
prompt.showToast({message: '需要联系人写入权限'})
}
} catch (err) {
prompt.showToast({message: `添加联系人失败: ${err.message}`})
}
}
build() {
Column() {
Button('获取联系人').onClick(() => {
this.getContacts()
}).margin(10)
Button('添加联系人').onClick(() => {
this.addContact()
}).margin(10)
List({space: 10}) {
ForEach(this.contacts, (item) => {
ListItem() {
Column() {
Text(item.name).fontSize(20)
Text(item.phone).fontSize(16).fontColor(Color.Gray)
}.width('100%').padding(10)
}
}, item => item.id.toString())
}.layoutWeight(1).width('100%')
}.width('100%').height('100%')
}
}
三、最佳实践与安全建议
- 最小权限原则:只申请必要的权限,并在manifest中明确说明权限用途。
- 动态权限检查:即使配置了静态权限,关键操作前仍应进行动态权限检查。
- 权限申请时机:在用户执行相关操作时申请权限,而非应用启动时一次性申请所有权限。
- 错误处理:妥善处理权限拒绝的情况,提供友好的用户引导。
- 数据加密:敏感数据应进行加密存储,即使获得数据访问权限也无法直接获取明文。
通过以上实践,开发者可以在HarmonyOS 5中构建安全可靠的DataAbility服务,确保用户数据得到充分保护。
更多推荐
所有评论(0)