HarmonyOS 5开发从入门到精通(十二):权限管理与安全
权限管理是HarmonyOS应用开发中至关重要的一环,它保护用户隐私和设备安全。本章将详细介绍权限申请、权限检查、敏感数据保护等安全相关功能。
一、权限系统概述
1.1 权限类型
HarmonyOS权限分为两大类:
普通权限:系统自动授予,无需用户确认
- 网络访问
- 振动
- 蓝牙
敏感权限:需要用户明确授权
- 相机
- 位置
- 麦克风
- 存储
- 通讯录
1.2 权限声明
在module.json5中声明所需权限:
{"requestPermissions": [{"name": "ohos.permission.CAMERA","reason": "需要拍照功能","usedScene": {"abilities": ["EntryAbility"],"when": "always"}},{"name": "ohos.permission.LOCATION","reason": "需要获取位置信息","usedScene": {"abilities": ["EntryAbility"],"when": "always"}}]
}
二、权限申请
2.1 单次权限申请
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';async function requestCameraPermission() {try {const atManager = abilityAccessCtrl.createAtManager();const permissions = ['ohos.permission.CAMERA'];const result = await atManager.requestPermissionsFromUser(getContext(),permissions);if (result.authResults[0] === 0) {console.log('相机权限已授权');return true;} else {console.log('相机权限被拒绝');return false;}} catch (error) {console.error('权限申请失败:', error);return false;}
}
2.2 批量权限申请
async function requestMultiplePermissions() {const atManager = abilityAccessCtrl.createAtManager();const permissions = ['ohos.permission.CAMERA','ohos.permission.MICROPHONE','ohos.permission.LOCATION'];const result = await atManager.requestPermissionsFromUser(getContext(),permissions);const granted = result.authResults.every(status => status === 0);return granted;
}
三、权限检查
3.1 检查权限状态
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';async function checkPermission(permission: string): Promise<boolean> {const atManager = abilityAccessCtrl.createAtManager();const result = await atManager.checkAccessToken(getContext(),permission);return result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
}// 使用示例
const hasCamera = await checkPermission('ohos.permission.CAMERA');
const hasLocation = await checkPermission('ohos.permission.LOCATION');
3.2 权限状态监听
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';function setupPermissionListener() {const atManager = abilityAccessCtrl.createAtManager();atManager.on('permissionChange', (permissionName, grantStatus) => {console.log(`权限 ${permissionName} 状态变为: ${grantStatus}`);if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {// 权限被授予,执行相关操作this.onPermissionGranted(permissionName);} else {// 权限被拒绝或撤销this.onPermissionDenied(permissionName);}});
}
四、权限使用最佳实践
4.1 按需申请权限
@Component
struct CameraComponent {@State hasCameraPermission: boolean = false;@State showPermissionDialog: boolean = false;async aboutToAppear() {this.hasCameraPermission = await this.checkCameraPermission();}async checkCameraPermission(): Promise<boolean> {const atManager = abilityAccessCtrl.createAtManager();const result = await atManager.checkAccessToken(getContext(),'ohos.permission.CAMERA');return result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;}async requestCameraPermission() {const atManager = abilityAccessCtrl.createAtManager();const result = await atManager.requestPermissionsFromUser(getContext(),['ohos.permission.CAMERA']);this.hasCameraPermission = result.authResults[0] === 0;if (!this.hasCameraPermission) {this.showPermissionDialog = true;}}openSettings() {// 引导用户去设置页面开启权限// 实际实现需要使用系统APIconsole.log('打开设置页面');}build() {Column() {if (this.hasCameraPermission) {// 显示相机功能Text('相机功能已开启').fontSize(16)} else {Button('开启相机权限').onClick(() => this.requestCameraPermission()).margin(20)}if (this.showPermissionDialog) {Text('需要相机权限才能使用拍照功能').fontSize(14).margin(10)Button('去设置').onClick(() => this.openSettings()).margin(10)}}}
}
五、数据加密与安全
5.1 数据加密存储
import cryptoFramework from '@ohos.security.cryptoFramework';async function encryptData(data: string, key: string): Promise<string> {try {const cipher = cryptoFramework.createCipher('AES256');const keyBlob = cryptoFramework.createKey(key);await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyBlob);const dataBlob = cryptoFramework.createDataBlob(data);const encryptedBlob = await cipher.doFinal(dataBlob);return encryptedBlob.toString();} catch (error) {console.error('加密失败:', error);throw error;}
}async function decryptData(encryptedData: string, key: string): Promise<string> {try {const cipher = cryptoFramework.createCipher('AES256');const keyBlob = cryptoFramework.createKey(key);await cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, keyBlob);const dataBlob = cryptoFramework.createDataBlob(encryptedData);const decryptedBlob = await cipher.doFinal(dataBlob);return decryptedBlob.toString();} catch (error) {console.error('解密失败:', error);throw error;}
}
5.2 安全存储敏感数据
import preferences from '@ohos.data.preferences';class SecureStorage {private prefs: preferences.Preferences | null = null;async init() {this.prefs = await preferences.getPreferences(getContext(), 'secure_data');}async saveSecureData(key: string, value: string) {if (!this.prefs) await this.init();await this.prefs!.put(key, value);await this.prefs!.flush();}async getSecureData(key: string): Promise<string | null> {if (!this.prefs) await this.init();return await this.prefs!.get(key, null);}async deleteSecureData(key: string) {if (!this.prefs) await this.init();await this.prefs!.delete(key);await this.prefs!.flush();}
}
六、网络安全
6.1 HTTPS请求
import http from '@ohos.net.http';async function secureHttpRequest(url: string, data: any) {try {const httpRequest = http.createHttp();const options = {method: http.RequestMethod.POST,header: {'Content-Type': 'application/json'},readTimeout: 30000,connectTimeout: 30000,usingProtocol: http.HttpProtocol.HTTPS // 强制使用HTTPS};const response = await httpRequest.request(url, options);if (response.responseCode === 200) {return JSON.parse(response.result);} else {throw new Error(`请求失败: ${response.responseCode}`);}} catch (error) {console.error('网络请求错误:', error);throw error;}
}
6.2 证书校验
import http from '@ohos.net.http';async function secureRequestWithCertPinning() {const httpRequest = http.createHttp();const options = {method: http.RequestMethod.GET,caPath: '/system/etc/security/cacerts', // 系统证书路径clientCert: {certPath: '/data/cert/client.pem',keyPath: '/data/cert/client.key'}};const response = await httpRequest.request('https://api.example.com', options);return response.result;
}
七、应用沙盒与数据隔离
7.1 应用沙盒目录
import fileio from '@ohos.fileio';// 获取应用沙盒目录
const context = getContext();
const filesDir = context.filesDir; // /data/app/包名/files
const cacheDir = context.cacheDir; // /data/app/包名/cache
const tempDir = context.tempDir; // /data/app/包名/temp
const databaseDir = context.databaseDir; // /data/app/包名/database
7.2 安全文件操作
import fs from '@ohos.file.fs';async function writeSecureFile(filename: string, content: string) {const filePath = `${getContext().filesDir}/${filename}`;try {// 检查文件是否存在let file = await fs.open(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);// 设置文件权限为私有await fs.chmod(filePath, 0o600);// 写入数据await fs.write(file.fd, content);await fs.close(file.fd);console.log('文件写入成功');} catch (error) {console.error('文件写入失败:', error);throw error;}
}
八、实战案例:权限管理组件
@Component
struct PermissionManager {@State cameraPermission: boolean = false;@State locationPermission: boolean = false;@State microphonePermission: boolean = false;async aboutToAppear() {await this.checkAllPermissions();}async checkAllPermissions() {this.cameraPermission = await this.checkPermission('ohos.permission.CAMERA');this.locationPermission = await this.checkPermission('ohos.permission.LOCATION');this.microphonePermission = await this.checkPermission('ohos.permission.MICROPHONE');}async checkPermission(permission: string): Promise<boolean> {const atManager = abilityAccessCtrl.createAtManager();const result = await atManager.checkAccessToken(getContext(), permission);return result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;}async requestPermission(permission: string): Promise<boolean> {const atManager = abilityAccessCtrl.createAtManager();const result = await atManager.requestPermissionsFromUser(getContext(), [permission]);return result.authResults[0] === 0;}build() {Column({ space: 15 }) {Text('权限管理').fontSize(20).fontWeight(FontWeight.Bold).margin({ bottom: 20 })this.buildPermissionItem('相机权限', this.cameraPermission, 'ohos.permission.CAMERA')this.buildPermissionItem('位置权限', this.locationPermission, 'ohos.permission.LOCATION')this.buildPermissionItem('麦克风权限', this.microphonePermission, 'ohos.permission.MICROPHONE')}.padding(20)}@BuilderbuildPermissionItem(label: string, granted: boolean, permission: string) {Row() {Text(label).fontSize(16).layoutWeight(1)if (granted) {Text('已授权').fontColor(Color.Green).fontSize(14)} else {Button('申请权限').onClick(async () => {const result = await this.requestPermission(permission);if (result) {await this.checkAllPermissions();}}).height(30)}}.width('100%').padding(10).backgroundColor('#F5F5F5').borderRadius(8)}
}
九、安全最佳实践
9.1 权限申请时机
推荐做法:
- 在用户需要使用功能时申请权限
- 提供清晰的权限说明
- 解释为什么需要该权限
避免做法:
- 应用启动时一次性申请所有权限
- 强制用户授权否则无法使用应用
9.2 数据保护
- 敏感数据加密存储
- 网络传输使用HTTPS
- 避免在日志中输出敏感信息
- 及时清理临时文件
9.3 代码混淆
在build-profile.json5中配置:
{"buildOption": {"proguard": {"enabled": true,"rules": "proguard-rules.pro"}}
}
十、总结
本章详细介绍了HarmonyOS的权限管理与安全开发:
✅ 权限系统 - 普通权限和敏感权限的区别
✅ 权限申请 - 单次和批量权限申请
✅ 权限检查 - 检查权限状态和监听变化
✅ 数据加密 - 敏感数据加密存储
✅ 网络安全 - HTTPS请求和证书校验
✅ 应用沙盒 - 安全文件操作和数据隔离
✅ 最佳实践 - 权限申请时机和数据保护
核心要点:
- 按需申请权限,不要一次性申请所有权限
- 敏感数据必须加密存储
- 网络请求必须使用HTTPS
- 及时清理临时文件和缓存
- 遵循最小权限原则
通过合理使用权限管理和安全技术,可以保护用户隐私,提升应用的安全性。