新增文件 (10): - data/models/user.dart — 用户+角色模型 (匹配后端 UserResp/RoleResp) - data/models/auth_token.dart — 认证令牌模型 (匹配后端 LoginResp) - data/repositories/auth_repository.dart — 认证仓库 (JWT 安全持久化 + PIPL 合规) - features/auth/bloc/auth_bloc.dart — 认证 BLoC (8 种事件, 6 种状态) - features/auth/bloc/auth_event.dart — 认证事件 (sealed class 穷尽匹配) - features/auth/bloc/auth_state.dart — 认证状态 (Authenticated 含角色/班级码流程) - features/auth/views/login_page.dart — 登录/注册页面 (重写占位页面) - features/auth/views/role_selection_page.dart — 角色选择页 (4 种角色卡片) - features/auth/views/class_code_join_page.dart — 班级码加入页 (6 位输入) 修改文件 (5): - pubspec.yaml — 添加 flutter_secure_storage 依赖 - app.dart — 注入 AuthBloc + RepositoryProvider - main.dart — 简化入口 (认证恢复在 BLoC 中处理) - core/routing/app_router.dart — 添加认证路由守卫 + 2 新路由 - erp-diary/service/class_service.rs — 移除未使用的 PaginatorTrait import 验证: flutter analyze (0 error) + cargo check 通过
55 lines
1.8 KiB
Dart
55 lines
1.8 KiB
Dart
// 认证令牌模型 — 匹配后端 LoginResp
|
||
//
|
||
// 管理访问令牌和刷新令牌,支持自动计算过期时间。
|
||
// 令牌通过 flutter_secure_storage 安全持久化(PIPL 合规要求)。
|
||
|
||
/// 认证令牌 — 包含访问令牌、刷新令牌和过期信息
|
||
class AuthToken {
|
||
final String accessToken;
|
||
final String refreshToken;
|
||
final int expiresIn;
|
||
final DateTime expiresAt;
|
||
|
||
const AuthToken({
|
||
required this.accessToken,
|
||
required this.refreshToken,
|
||
required this.expiresIn,
|
||
required this.expiresAt,
|
||
});
|
||
|
||
/// 令牌是否已过期
|
||
bool get isExpired => DateTime.now().isAfter(expiresAt);
|
||
|
||
/// 令牌是否即将过期(5 分钟内)
|
||
bool get isExpiringSoon =>
|
||
DateTime.now().isAfter(expiresAt.subtract(const Duration(minutes: 5)));
|
||
|
||
/// 从后端 LoginResp JSON 创建
|
||
factory AuthToken.fromJson(Map<String, dynamic> json) {
|
||
final expiresIn = (json['expires_in'] as int?) ?? 3600;
|
||
return AuthToken(
|
||
accessToken: json['access_token'] as String,
|
||
refreshToken: json['refresh_token'] as String,
|
||
expiresIn: expiresIn,
|
||
expiresAt: DateTime.now().add(Duration(seconds: expiresIn)),
|
||
);
|
||
}
|
||
|
||
Map<String, dynamic> toJson() => {
|
||
'access_token': accessToken,
|
||
'refresh_token': refreshToken,
|
||
'expires_in': expiresIn,
|
||
'expires_at': expiresAt.toIso8601String(),
|
||
};
|
||
|
||
/// 从持久化存储恢复(使用保存的过期时间)
|
||
factory AuthToken.fromStorage(Map<String, dynamic> json) => AuthToken(
|
||
accessToken: json['access_token'] as String,
|
||
refreshToken: json['refresh_token'] as String,
|
||
expiresIn: (json['expires_in'] as int?) ?? 3600,
|
||
expiresAt: json['expires_at'] != null
|
||
? DateTime.parse(json['expires_at'] as String)
|
||
: DateTime.now().add(const Duration(hours: 1)),
|
||
);
|
||
}
|