开源鸿蒙跨平台:Flutter 登录退出与身份识别
同时做了数据去重、空值兜底、异常捕获,是连接业务层与本地存储的桥梁,所有存储方法均为静态方法,业务层可直接调用,无需实例化。▸ auth_service.dart 是基础依赖层:提供登录、Token 校验、用户信息获取能力,为其他模块提供用户鉴权数据;▸ persistence_storage.dart 是业务存储层:依赖认证服务的用户信息,实现多用户隔离的本地数据存储;▸ api_client.
核心模式
1. 服务模式 (Service Pattern)
-
AuthService: 负责所有认证相关操作 -
PersistenceStorage: 负责本地数据持久化 -
GitCodeApiClient: 负责网络API通信
2. 状态管理 (State Management)
-
使用
setState进行组件级状态管理 -
使用
Stream进行异步数据流管理 -
使用
SharedPreferences进行持久化状态存储
3. 依赖解耦 (Dependency Decoupling)
-
API客户端不直接依赖AuthService,通过SharedPreferences间接获取Token
-
各服务之间通过接口和回调进行通信,避免紧耦合
用户操作 → UI层 → 业务逻辑层 → 数据层 → 状态更新
↓ ↓ ↓ ↓ ↓
点击登录 → LoginPage → AuthService → API验证 → 保存Token
↓ ↓ ↓ ↓ ↓
收藏仓库 → DetailPage → Persistence → SharedPrefs → 更新UI
↓ ↓ ↓ ↓ ↓
查看收藏 → ProfilePage → 读取存储 → 聚合数据 → 显示统计
🛠️ 关键技术点
1. Token安全策略
// 安全策略:
// 1. Token不存储在代码中
// 2. 验证通过后才持久化
// 3. 每次API请求都携带Token
// 4. Token无效时自动引导重新登录
2. 多用户数据隔离
// 数据隔离机制:
// 键格式:${username}_${dataType}
// 示例:john_doe_starred_repositories
// 优势:支持多账户切换,数据互不干扰

代码组织结构
lib/
├── main.dart # 应用入口,认证包装器
├── services/
│ ├── auth_service.dart # 认证服务核心
│ ├── persistence_storage.dart # 持久化存储
│ └── app_init.dart # 应用初始化
├── core/
│ ├── api_client.dart # API客户端
│ └── models/ # 数据模型
├── pages/
│ ├── login_page.dart # 登录页面
│ ├── home_page.dart # 首页
│ ├── profile_page.dart # 个人中心
│ ├── repository_detail_page.dart # 仓库详情
│ └── user_detail_page.dart # 用户详情
└── widgets/ # 可复用组件
▸ auth_service.dart 是基础依赖层:提供登录、Token 校验、用户信息获取能力,为其他模块提供用户鉴权数据;
▸ persistence_storage.dart 是业务存储层:依赖认证服务的用户信息,实现多用户隔离的本地数据存储;
▸ api_client.dart 是网络请求层:独立读取本地 Token,实现无依赖的接口请求,为业务层提供服务端数据;
关键代码详解
1. 认证服务 (auth_service.dart)
该模块封装了「登录、Token 有效性校验、用户信息持久化、用户信息读取」等所有认证相关逻辑,是用户体系的基础;所有方法均为异步实现,包含完整的异常捕获与兜底处理,返回统一的认证结果模型,业务层可直接根据结果做逻辑处理。
// 登录方法实现
Future<AuthResult> login(String token) async {
try {
final prefs = await SharedPreferences.getInstance();
// 1. 临时保存Token以供验证
await prefs.setString(_tokenKey, token);
// 2. 使用Token获取用户信息验证有效性
final user = await GitCodeApiClient().getCurrentUser();
// 3. 验证成功后持久化保存
await prefs.setString(_usernameKey, user.login);
await prefs.setString(_userKey, _userToJson(user));
return AuthResult.success(user);
} catch (e) {
// 4. 验证失败则清理临时数据
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_tokenKey);
return AuthResult.failure('登录失败: ${e.toString()}');
}
}
// Token验证机制
Future<bool> validateToken(String token) async {
if (token.isEmpty) return false;
final uri = Uri.parse('$baseUrl/user').replace(
queryParameters: {'access_token': token},
);
try {
final response = await http.get(uri).timeout(const Duration(seconds: 10));
return response.statusCode == 200; // 200表示Token有效
} catch (e) {
return false;
}
}
-
临时Token策略:先保存Token进行验证,验证成功才持久化,防止无效Token污染存储
-
双向验证:通过调用API接口验证Token,同时获取用户信息
-
错误回滚:验证失败时清理临时数据,确保状态一致性
2. 持久化存储系统 (persistence_storage.dart)
该模块基于鸿蒙适配版 SharedPreferences 封装,核心承载「收藏仓库、关注用户」等私有业务数据的增删查操作;同时做了数据去重、空值兜底、异常捕获,是连接业务层与本地存储的桥梁,所有存储方法均为静态方法,业务层可直接调用,无需实例化。
// 用户隔离的存储键生成
static Future<String> _getUserKey(String baseKey) async {
final username = await _authService.getCurrentUsername();
if (username == null) {
throw Exception('用户未登录');
}
return '${username}_$baseKey'; // 如: "john_doe_starred_repositories"
}
// 收藏仓库实现
static Future<void> starRepository(String repoFullName) async {
final prefs = await SharedPreferences.getInstance();
final key = await _getUserKey('starred_repositories');
final starred = prefs.getStringList(key) ?? [];
// 去重检查
if (!starred.contains(repoFullName)) {
starred.add(repoFullName);
await prefs.setStringList(key, starred);
}
}
// 检查收藏状态
static Future<bool> isRepositoryStarred(String repoFullName) async {
try {
final prefs = await SharedPreferences.getInstance();
final key = await _getUserKey('starred_repositories');
final starred = prefs.getStringList(key) ?? [];
return starred.contains(repoFullName); // 检查是否在列表中
} catch (e) {
return false; // 出错时默认为未收藏
}
}
-
用户隔离:每个用户的收藏/关注数据使用用户名作为前缀,实现多用户数据隔离
-
数据去重:添加时检查是否已存在,避免重复数据
-
错误处理:读取失败时返回默认值,避免应用崩溃
-
键名规范:使用统一命名规范,便于管理和维护
3. API客户端Token管理 (api_client.dart)
封装了所有 GitCode 开放平台的接口请求,核心处理「接口地址拼接、请求参数封装、Token 自动携带、数据解析、异常处理」等逻辑;API 客户端不依赖任何业务服务,直接从本地存储读取 Token,是所有业务层获取服务端数据的统一入口。
// Token获取方法(不依赖AuthService,打破循环依赖)
Future<String?> _getToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('user_token'); // 直接从SharedPrefs获取
}
// 所有API请求中的Token应用
Future<List<GitCodeRepository>> searchRepositories({
required String keyword,
int page = 1,
int perPage = 20,
}) async {
final token = await _getToken(); // 获取Token
if (token == null || token.isEmpty) {
throw Exception('请先登录获取访问令牌'); // Token检查
}
final uri = Uri.parse('$baseUrl/search/repositories').replace(
queryParameters: {
'q': keyword,
'page': page.toString(),
'per_page': perPage.toString(),
'access_token': token, // Token作为查询参数
},
);
// ... 发起请求
}
-
解耦设计:API客户端直接读取SharedPreferences,避免与AuthService循环依赖
-
统一Token管理:所有API请求前都检查Token有效性
-
异常处理:Token无效时抛出明确异常,引导用户重新登录



欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)