HarmonyOS 5开发从入门到精通(十二):权限管理与安全

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() {
    // 引导用户去设置页面开启权限
    // 实际实现需要使用系统API
    console.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)
  }
  
  @Builder
  buildPermissionItem(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请求和证书校验

应用沙盒 - 安全文件操作和数据隔离

最佳实践 - 权限申请时机和数据保护

核心要点

  1. 按需申请权限,不要一次性申请所有权限
  2. 敏感数据必须加密存储
  3. 网络请求必须使用HTTPS
  4. 及时清理临时文件和缓存
  5. 遵循最小权限原则

通过合理使用权限管理和安全技术,可以保护用户隐私,提升应用的安全性。


posted @ 2025-12-23 21:03  奇崽  阅读(0)  评论(0)    收藏  举报