二次开发源码提交

This commit is contained in:
2026-05-15 08:52:48 +08:00
parent 4131f7321a
commit eb35a1d067
191 changed files with 34566 additions and 0 deletions
@@ -0,0 +1,333 @@
import 'package:cloudreve4_flutter/presentation/widgets/toast_helper.dart';
import 'package:cloudreve4_flutter/presentation/widgets/user_avatar.dart';
import 'package:flutter/foundation.dart';
import '../../data/models/server_model.dart';
import '../../data/models/user_model.dart';
import '../../services/auth_service.dart';
import '../../services/server_service.dart';
import '../../services/storage_service.dart';
import '../../services/api_service.dart';
import '../../core/exceptions/app_exception.dart';
import '../../core/utils/app_logger.dart';
/// 认证状态
enum AuthState { loading, authenticated, unauthenticated, error }
/// 认证Provider
class AuthProvider extends ChangeNotifier {
AuthState _state = AuthState.unauthenticated;
UserModel? _user;
String? _errorMessage;
bool _hasRefreshTokenExpired = false;
AuthState get state => _state;
UserModel? get user => _user;
String? get errorMessage => _errorMessage;
bool get isAuthenticated => _state == AuthState.authenticated;
bool get isLoading => _state == AuthState.loading;
bool get hasRefreshTokenExpired => _hasRefreshTokenExpired;
bool get isAdmin {
final name = _user?.group?.name.toLowerCase();
return name == 'admin' || name == '管理员';
}
/// 当前选中的服务器
ServerModel? get currentServer => ServerService.instance.currentServer;
/// 获取当前用户的 token
TokenModel? get token => _user?.token;
/// 初始化
Future<void> init() async {
try {
setState(AuthState.loading);
// 初始化服务器服务
await ServerService.instance.init();
// 获取当前服务器
final server = ServerService.instance.currentServer;
if (server == null) {
setState(AuthState.unauthenticated);
return;
}
// 设置 API 的 baseUrl
await _setApiBaseUrl(server.baseUrl);
// 设置 ApiService 的认证回调
_setupApiCallbacks();
// 检查是否有保存的登录信息
if (server.user != null && server.user!.token != null) {
// 有保存的用户信息,检查 token 是否过期
if (!server.user!.token!.isRefreshTokenExpired) {
// Refresh token 未过期,设置用户信息
setUser(server.user);
setState(AuthState.authenticated);
return;
} else {
// Refresh token 已过期,清除登录信息
await ServerService.instance.clearCurrentServerLogin();
}
}
_user = null;
setState(AuthState.unauthenticated);
} catch (e) {
AppLogger.d('AuthProvider 初始化失败: $e');
_user = null;
setState(AuthState.unauthenticated);
}
}
/// 设置 ApiService 的认证回调
void _setupApiCallbacks() {
ApiService.setAuthCallbacks(
getToken: () async {
// 返回当前的 access token
return _user?.token?.accessToken;
},
refreshToken: () async {
// 刷新 token
try {
await refreshToken();
} catch (e) {
// 刷新失败,设置过期标志
if (e is RefreshTokenExpiredException) {
setRefreshTokenExpired();
}
rethrow;
}
},
clearAuth: () async {
// 清除认证数据
await ServerService.instance.clearCurrentServerLogin();
setRefreshTokenExpired();
},
);
}
/// 设置 API baseUrl
Future<void> _setApiBaseUrl(String baseUrl) async {
// 同时更新存储和 ApiService 的 baseUrl
final storageService = StorageService.instance;
await storageService.setCustomBaseUrl(baseUrl);
await ApiService.instance.setBaseUrl(baseUrl);
}
/// 密码登录
Future<bool> passwordLogin({
required String email,
required String password,
bool rememberMe = false,
}) async {
try {
setState(AuthState.loading);
// 获取当前服务器
final server = ServerService.instance.currentServer;
if (server == null) {
_errorMessage = '服务器初始化失败';
_user = null;
setState(AuthState.error);
return false;
}
// 每次登录时都重新设置 API 的 baseUrl,确保使用最新的服务器地址
await _setApiBaseUrl(server.baseUrl);
// 执行登录
final response = await AuthService.instance.passwordLogin(
email: email,
password: password,
);
AppLogger.d('AuthProvider 登录成功: $response');
// 保存登录信息到当前服务器(包含完整 user 和 token
await ServerService.instance.updateCurrentServerLogin(
email: rememberMe ? email : null,
password: rememberMe ? password : null,
user: response.user,
rememberMe: rememberMe,
);
setUser(response.user);
setState(AuthState.authenticated);
return true;
} on TwoFactorRequiredException {
// 两步验证需要,不设置 error 状态,重新抛出让调用方处理
setState(AuthState.unauthenticated);
rethrow;
} catch (e) {
_errorMessage = e.toString();
_user = null;
setState(AuthState.error);
return false;
}
}
/// 两步验证登录
Future<bool> twoFactorLogin({
required String otp,
required String sessionId,
required String email,
required String password,
bool rememberMe = false,
}) async {
try {
setState(AuthState.loading);
final response = await AuthService.instance.twoFactorLogin(
otp: otp,
sessionId: sessionId,
);
await ServerService.instance.updateCurrentServerLogin(
email: rememberMe ? email : null,
password: rememberMe ? password : null,
user: response.user,
rememberMe: rememberMe,
);
setUser(response.user);
setState(AuthState.authenticated);
return true;
} catch (e) {
_errorMessage = e.toString();
_user = null;
setState(AuthState.error);
return false;
}
}
/// 登出
Future<void> logout() async {
try {
// 调用登出 API(需要 token
if (token?.refreshToken != null) {
try {
await AuthService.instance.logout();
} catch (e) {
// 登出 API 调用失败不影响本地清理
AppLogger.d('登出 API 调用失败: $e');
}
}
// 清除当前服务器的登录信息
await ServerService.instance.clearCurrentServerLogin();
_clearUserData();
// 清除头像缓存
await UserAvatar.clearAllCache();
setState(AuthState.unauthenticated);
} catch (e) {
// 即使出错也要清除本地状态
_clearUserData();
setState(AuthState.unauthenticated);
_errorMessage = e.toString();
}
}
/// 刷新用户信息
Future<void> refreshUser() async {
try {
final user = await AuthService.instance.getCurrentUser();
setUser(user);
// 更新服务器中的用户信息(保留 token)
final server = ServerService.instance.currentServer;
if (server != null && token != null) {
await ServerService.instance.updateCurrentServerLogin(
user: user.copyWith(token: token),
);
}
} catch (e) {
_errorMessage = e.toString();
}
}
/// 刷新 token
Future<void> refreshToken() async {
try {
final currentToken = token;
if (currentToken == null || currentToken.isRefreshTokenExpired) {
ToastHelper.failure('已注销或Refresh token 已过期,需要重新登录');
throw Exception('Refresh token 已过期,需要重新登录');
}
// 调用刷新 token 接口
final newToken = await AuthService.instance.refreshToken(currentToken.refreshToken);
// 更新用户信息中的 token
final updatedUser = _user!.copyWith(token: newToken);
// 保存到服务器
await ServerService.instance.updateCurrentServerLogin(user: updatedUser);
setUser(updatedUser);
} catch (e) {
ToastHelper.error('刷新 token 失败: $e');
AppLogger.d('刷新 token 失败: $e');
_user = null;
_errorMessage = e.toString();
notifyListeners();
rethrow;
}
}
/// 设置用户
void setUser(UserModel? user) {
_user = user;
notifyListeners();
}
/// 设置状态
void setState(AuthState state) {
_state = state;
notifyListeners();
}
/// 清除错误
void clearError() {
_errorMessage = null;
notifyListeners();
}
/// 清除用户数据
void _clearUserData() {
_user = null;
_errorMessage = null;
_hasRefreshTokenExpired = false;
notifyListeners();
}
/// 处理 RefreshTokenExpiredException
void setRefreshTokenExpired() {
_hasRefreshTokenExpired = true;
notifyListeners();
}
void clearRefreshTokenExpired() {
_hasRefreshTokenExpired = false;
notifyListeners();
}
/// 获取上次登录的邮箱(用于填充输入框)
String? get rememberedEmail {
final server = ServerService.instance.currentServer;
return server?.email;
}
/// 获取上次登录的密码(用于填充输入框)
String? get rememberedPassword {
final server = ServerService.instance.currentServer;
return server?.password;
}
/// 是否记住密码
bool get rememberMe {
final server = ServerService.instance.currentServer;
return server?.rememberMe ?? false;
}
}