
引言
安全存储是应用开发中保护敏感数据的重要手段。本文将介绍如何封装一个安全存储系统,包括:
- 安全存储API封装
- 数据加密存储
- Token管理
- 敏感数据保护
通过本文,你将掌握如何构建安全的存储系统。
学习目标
完成本文后,你将能够:
- ✅ 封装安全存储API
- ✅ 实现数据加密
- ✅ 管理Token
- ✅ 保护敏感数据
需求分析
功能模块设计
| 模块 | 功能描述 | 技术要点 |
|---|---|---|
| 安全存储 | 封装安全存储API | 数据加密、解密 |
| Token管理 | 管理用户Token | Token存储、获取、清除 |
| 数据加密 | 加密敏感数据 | AES加密、Base64编码 |
| 密钥管理 | 管理加密密钥 | 密钥生成、存储 |
核心实现
步骤1: 安全存储API封装
typescript
// storage/SecureStorage.ets
import { logger } from '../utils/Logger';
/**
* 安全存储服务
*/
class SecureStorage {
private static instance: SecureStorage;
// 存储前缀
private prefix: string = 'app_';
/**
* 获取单例实例
*/
static getInstance(): SecureStorage {
if (!SecureStorage.instance) {
SecureStorage.instance = new SecureStorage();
}
return SecureStorage.instance;
}
/**
* 设置存储前缀
*/
setPrefix(prefix: string): void {
this.prefix = prefix;
}
/**
* 获取完整的存储键名
*/
private getKey(key: string): string {
return `${this.prefix}${key}`;
}
/**
* 存储字符串
*/
async setString(key: string, value: string): Promise<void> {
try {
await storage.set(this.getKey(key), value);
logger.debug(`存储字符串: ${key}`);
} catch (error) {
logger.error(`存储字符串失败: ${key}`, error);
throw error;
}
}
/**
* 获取字符串
*/
async getString(key: string, defaultValue: string = ''): Promise<string> {
try {
const value = await storage.get(this.getKey(key), defaultValue);
logger.debug(`获取字符串: ${key}`);
return value;
} catch (error) {
logger.error(`获取字符串失败: ${key}`, error);
return defaultValue;
}
}
/**
* 存储数字
*/
async setNumber(key: string, value: number): Promise<void> {
await this.setString(key, value.toString());
}
/**
* 获取数字
*/
async getNumber(key: string, defaultValue: number = 0): Promise<number> {
const value = await this.getString(key, defaultValue.toString());
return parseFloat(value);
}
/**
* 存储布尔值
*/
async setBoolean(key: string, value: boolean): Promise<void> {
await this.setString(key, value ? 'true' : 'false');
}
/**
* 获取布尔值
*/
async getBoolean(key: string, defaultValue: boolean = false): Promise<boolean> {
const value = await this.getString(key, defaultValue ? 'true' : 'false');
return value === 'true';
}
/**
* 存储对象
*/
async setObject<T>(key: string, value: T): Promise<void> {
try {
const jsonString = JSON.stringify(value);
await this.setString(key, jsonString);
logger.debug(`存储对象: ${key}`);
} catch (error) {
logger.error(`存储对象失败: ${key}`, error);
throw error;
}
}
/**
* 获取对象
*/
async getObject<T>(key: string, defaultValue: T | null = null): Promise<T | null> {
try {
const jsonString = await this.getString(key);
if (!jsonString) {
return defaultValue;
}
const value = JSON.parse(jsonString) as T;
logger.debug(`获取对象: ${key}`);
return value;
} catch (error) {
logger.error(`获取对象失败: ${key}`, error);
return defaultValue;
}
}
/**
* 删除存储项
*/
async remove(key: string): Promise<void> {
try {
await storage.delete(this.getKey(key));
logger.debug(`删除存储项: ${key}`);
} catch (error) {
logger.error(`删除存储项失败: ${key}`, error);
throw error;
}
}
/**
* 清除所有存储
*/
async clear(): Promise<void> {
try {
await storage.clear();
logger.debug('清除所有存储');
} catch (error) {
logger.error('清除存储失败', error);
throw error;
}
}
/**
* 检查存储项是否存在
*/
async contains(key: string): Promise<boolean> {
try {
const value = await this.getString(key);
return value !== '';
} catch {
return false;
}
}
}
// Mock storage API
const storage = {
async set(key: string, value: string): Promise<void> {},
async get(key: string, defaultValue: string): Promise<string> {
return defaultValue;
},
async delete(key: string): Promise<void> {},
async clear(): Promise<void> {}
};
/**
* 全局安全存储实例
*/
export const secureStorage = SecureStorage.getInstance();
/**
* 便捷存储方法
*/
export const Storage = {
set: secureStorage.setString.bind(secureStorage),
get: secureStorage.getString.bind(secureStorage),
setObject: secureStorage.setObject.bind(secureStorage),
getObject: secureStorage.getObject.bind(secureStorage),
remove: secureStorage.remove.bind(secureStorage),
clear: secureStorage.clear.bind(secureStorage)
};
设计要点:
- 统一存储接口
- 支持多种数据类型
- 错误处理和日志记录
步骤2: 加密存储服务
typescript
// storage/EncryptedStorage.ets
import { logger } from '../utils/Logger';
/**
* 加密存储服务
*/
class EncryptedStorage {
private static instance: EncryptedStorage;
// 加密密钥(应该从安全渠道获取)
private encryptionKey: string = 'default_encryption_key_12345';
/**
* 获取单例实例
*/
static getInstance(): EncryptedStorage {
if (!EncryptedStorage.instance) {
EncryptedStorage.instance = new EncryptedStorage();
}
return EncryptedStorage.instance;
}
/**
* 设置加密密钥
*/
setEncryptionKey(key: string): void {
this.encryptionKey = key;
}
/**
* 加密数据
*/
private encrypt(data: string): string {
try {
// 简单的加密实现(实际应用中应使用更安全的加密算法)
let encrypted = '';
for (let i = 0; i < data.length; i++) {
const charCode = data.charCodeAt(i);
const keyCode = this.encryptionKey.charCodeAt(i % this.encryptionKey.length);
encrypted += String.fromCharCode(charCode ^ keyCode);
}
// Base64编码
return this.base64Encode(encrypted);
} catch (error) {
logger.error('加密失败', error);
throw error;
}
}
/**
* 解密数据
*/
private decrypt(data: string): string {
try {
// Base64解码
const decoded = this.base64Decode(data);
// 解密
let decrypted = '';
for (let i = 0; i < decoded.length; i++) {
const charCode = decoded.charCodeAt(i);
const keyCode = this.encryptionKey.charCodeAt(i % this.encryptionKey.length);
decrypted += String.fromCharCode(charCode ^ keyCode);
}
return decrypted;
} catch (error) {
logger.error('解密失败', error);
throw error;
}
}
/**
* Base64编码
*/
private base64Encode(str: string): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
let result = '';
let i = 0;
while (i < str.length) {
const char1 = str.charCodeAt(i++) || 0;
const char2 = str.charCodeAt(i++) || 0;
const char3 = str.charCodeAt(i++) || 0;
const enc1 = char1 >> 2;
const enc2 = ((char1 & 3) << 4) | (char2 >> 4);
const enc3 = ((char2 & 15) << 2) | (char3 >> 6);
const enc4 = char3 & 63;
if (isNaN(char2)) enc3 = enc4 = 64;
else if (isNaN(char3)) enc4 = 64;
result += chars[enc1] + chars[enc2] + chars[enc3] + chars[enc4];
}
return result;
}
/**
* Base64解码
*/
private base64Decode(str: string): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
let result = '';
let i = 0;
str = str.replace(/[^A-Za-z0-9+/=]/g, '');
while (i < str.length) {
const enc1 = chars.indexOf(str.charAt(i++));
const enc2 = chars.indexOf(str.charAt(i++));
const enc3 = chars.indexOf(str.charAt(i++));
const enc4 = chars.indexOf(str.charAt(i++));
const char1 = (enc1 << 2) | (enc2 >> 4);
const char2 = ((enc2 & 15) << 4) | (enc3 >> 2);
const char3 = ((enc3 & 3) << 6) | enc4;
result += String.fromCharCode(char1);
if (enc3 !== 64) result += String.fromCharCode(char2);
if (enc4 !== 64) result += String.fromCharCode(char3);
}
return result;
}
/**
* 存储加密数据
*/
async setEncrypted(key: string, value: string): Promise<void> {
try {
const encrypted = this.encrypt(value);
await storage.set(key, encrypted);
logger.debug(`存储加密数据: ${key}`);
} catch (error) {
logger.error(`存储加密数据失败: ${key}`, error);
throw error;
}
}
/**
* 获取加密数据
*/
async getEncrypted(key: string, defaultValue: string = ''): Promise<string> {
try {
const encrypted = await storage.get(key, '');
if (!encrypted) {
return defaultValue;
}
const decrypted = this.decrypt(encrypted);
logger.debug(`获取加密数据: ${key}`);
return decrypted;
} catch (error) {
logger.error(`获取加密数据失败: ${key}`, error);
return defaultValue;
}
}
/**
* 存储加密对象
*/
async setEncryptedObject<T>(key: string, value: T): Promise<void> {
const jsonString = JSON.stringify(value);
await this.setEncrypted(key, jsonString);
}
/**
* 获取加密对象
*/
async getEncryptedObject<T>(key: string, defaultValue: T | null = null): Promise<T | null> {
const jsonString = await this.getEncrypted(key);
if (!jsonString) {
return defaultValue;
}
try {
return JSON.parse(jsonString) as T;
} catch {
return defaultValue;
}
}
}
// Mock storage API
const storage = {
async set(key: string, value: string): Promise<void> {},
async get(key: string, defaultValue: string): Promise<string> {
return defaultValue;
}
};
/**
* 全局加密存储实例
*/
export const encryptedStorage = EncryptedStorage.getInstance();
设计要点:
- XOR加密算法
- Base64编码
- 加密对象存储
步骤3: Token管理器
typescript
// storage/TokenManager.ets
import { logger } from '../utils/Logger';
import { secureStorage, encryptedStorage } from './SecureStorage';
/**
* Token管理器
*/
class TokenManager {
private static instance: TokenManager;
// Token存储键名
private static readonly ACCESS_TOKEN_KEY = 'access_token';
private static readonly REFRESH_TOKEN_KEY = 'refresh_token';
private static readonly TOKEN_EXPIRE_KEY = 'token_expire';
private static readonly USER_INFO_KEY = 'user_info';
/**
* 获取单例实例
*/
static getInstance(): TokenManager {
if (!TokenManager.instance) {
TokenManager.instance = new TokenManager();
}
return TokenManager.instance;
}
/**
* 设置Token
*/
async setToken(accessToken: string, refreshToken: string, expireTime: number): Promise<void> {
try {
// 使用加密存储保存Token
await encryptedStorage.setEncrypted(TokenManager.ACCESS_TOKEN_KEY, accessToken);
await encryptedStorage.setEncrypted(TokenManager.REFRESH_TOKEN_KEY, refreshToken);
await secureStorage.setNumber(TokenManager.TOKEN_EXPIRE_KEY, expireTime);
logger.info('Token设置成功');
} catch (error) {
logger.error('Token设置失败', error);
throw error;
}
}
/**
* 获取Access Token
*/
async getAccessToken(): Promise<string | null> {
try {
// 检查Token是否过期
if (await this.isTokenExpired()) {
// 尝试刷新Token
const refreshed = await this.refreshToken();
if (refreshed) {
return await encryptedStorage.getEncrypted(TokenManager.ACCESS_TOKEN_KEY);
}
return null;
}
return await encryptedStorage.getEncrypted(TokenManager.ACCESS_TOKEN_KEY);
} catch (error) {
logger.error('获取Access Token失败', error);
return null;
}
}
/**
* 获取Refresh Token
*/
async getRefreshToken(): Promise<string | null> {
try {
return await encryptedStorage.getEncrypted(TokenManager.REFRESH_TOKEN_KEY);
} catch (error) {
logger.error('获取Refresh Token失败', error);
return null;
}
}
/**
* 检查Token是否过期
*/
async isTokenExpired(): Promise<boolean> {
try {
const expireTime = await secureStorage.getNumber(TokenManager.TOKEN_EXPIRE_KEY);
const now = Date.now();
return expireTime > 0 && now >= expireTime;
} catch {
return true;
}
}
/**
* 刷新Token
*/
async refreshToken(): Promise<boolean> {
try {
const refreshToken = await this.getRefreshToken();
if (!refreshToken) {
return false;
}
// 调用刷新Token API
// const response = await httpService.post('/api/refresh', { refreshToken });
// if (response.success) {
// await this.setToken(response.data.accessToken, response.data.refreshToken, response.data.expireTime);
// return true;
// }
// 模拟刷新失败
logger.warn('Token刷新失败,需要重新登录');
await this.clearToken();
return false;
} catch (error) {
logger.error('Token刷新失败', error);
await this.clearToken();
return false;
}
}
/**
* 清除Token
*/
async clearToken(): Promise<void> {
try {
await secureStorage.remove(TokenManager.ACCESS_TOKEN_KEY);
await secureStorage.remove(TokenManager.REFRESH_TOKEN_KEY);
await secureStorage.remove(TokenManager.TOKEN_EXPIRE_KEY);
await secureStorage.remove(TokenManager.USER_INFO_KEY);
logger.info('Token已清除');
} catch (error) {
logger.error('清除Token失败', error);
throw error;
}
}
/**
* 检查是否已登录
*/
async isLoggedIn(): Promise<boolean> {
const token = await this.getAccessToken();
return !!token;
}
/**
* 设置用户信息
*/
async setUserInfo(userInfo: UserInfo): Promise<void> {
await secureStorage.setObject(TokenManager.USER_INFO_KEY, userInfo);
}
/**
* 获取用户信息
*/
async getUserInfo(): Promise<UserInfo | null> {
return await secureStorage.getObject<UserInfo>(TokenManager.USER_INFO_KEY);
}
}
interface UserInfo {
id: string;
name: string;
avatar: string;
email: string;
}
/**
* 全局Token管理器实例
*/
export const tokenManager = TokenManager.getInstance();
设计要点:
- Token存储和管理
- Token过期检查
- Token刷新机制
步骤4: 在应用中使用安全存储
typescript
// 在应用中使用安全存储
import { secureStorage, encryptedStorage } from './storage/SecureStorage';
import { tokenManager } from './storage/TokenManager';
@Entry
@Component
struct LoginPage {
@State username: string = '';
@State password: string = '';
async onLogin() {
try {
// 调用登录API
// const response = await httpService.post('/api/login', {
// username: this.username,
// password: this.password
// });
// 模拟登录成功
const mockResponse = {
accessToken: 'mock_access_token',
refreshToken: 'mock_refresh_token',
expireTime: Date.now() + 3600 * 1000 * 24, // 24小时后过期
userInfo: {
id: '1',
name: '用户A',
avatar: '',
email: 'user@example.com'
}
};
// 保存Token
await tokenManager.setToken(
mockResponse.accessToken,
mockResponse.refreshToken,
mockResponse.expireTime
);
// 保存用户信息
await tokenManager.setUserInfo(mockResponse.userInfo);
// 跳转到首页
// router.pushUrl({ url: 'pages/Home' });
} catch (error) {
console.error('登录失败:', error);
}
}
async onLogout() {
// 清除Token
await tokenManager.clearToken();
// 跳转到登录页
// router.pushUrl({ url: 'pages/Login' });
}
async checkLoginStatus() {
const isLoggedIn = await tokenManager.isLoggedIn();
if (!isLoggedIn) {
// 跳转到登录页
// router.pushUrl({ url: 'pages/Login' });
}
}
build() {
Column({ space: 16 }) {
TextInput({ placeholder: '用户名' })
.onChange((value: string) => this.username = value)
TextInput({ placeholder: '密码' })
.type(InputType.Password)
.onChange((value: string) => this.password = value)
Button('登录')
.onClick(() => this.onLogin())
Button('退出登录')
.onClick(() => this.onLogout())
}
.width('100%')
.height('100%')
.padding(16)
.justifyContent(FlexAlign.Center)
}
}
设计要点:
- 登录时保存Token
- 退出时清除Token
- 检查登录状态
本章小结
核心知识点
本文完成了安全存储封装:
1. 安全存储API
- 统一存储接口
- 支持多种数据类型
- 错误处理和日志记录
2. 加密存储服务
- XOR加密算法
- Base64编码
- 加密对象存储
3. Token管理器
- Token存储和管理
- Token过期检查
- Token刷新机制