init
This commit is contained in:
312
client/lib/features/auth/providers/auth_provider.dart
Normal file
312
client/lib/features/auth/providers/auth_provider.dart
Normal file
@@ -0,0 +1,312 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../../core/models/user_model.dart';
|
||||
import '../../../core/services/auth_service.dart';
|
||||
import '../../../core/services/storage_service.dart';
|
||||
import '../../../core/network/api_client.dart';
|
||||
import '../../../core/errors/app_exception.dart';
|
||||
|
||||
/// 认证状态
|
||||
class AuthState {
|
||||
final User? user;
|
||||
final bool isAuthenticated;
|
||||
final bool isLoading;
|
||||
final String? error;
|
||||
|
||||
const AuthState({
|
||||
this.user,
|
||||
this.isAuthenticated = false,
|
||||
this.isLoading = false,
|
||||
this.error,
|
||||
});
|
||||
|
||||
AuthState copyWith({
|
||||
User? user,
|
||||
bool? isAuthenticated,
|
||||
bool? isLoading,
|
||||
String? error,
|
||||
}) {
|
||||
return AuthState(
|
||||
user: user ?? this.user,
|
||||
isAuthenticated: isAuthenticated ?? this.isAuthenticated,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
error: error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 认证状态管理器
|
||||
class AuthNotifier extends StateNotifier<AuthState> {
|
||||
final AuthService _authService;
|
||||
final StorageService _storageService;
|
||||
|
||||
AuthNotifier(this._authService, this._storageService) : super(const AuthState()) {
|
||||
_checkAuthStatus();
|
||||
}
|
||||
|
||||
/// 检查认证状态
|
||||
Future<void> _checkAuthStatus() async {
|
||||
try {
|
||||
final token = await _storageService.getToken();
|
||||
if (token != null && token.isNotEmpty) {
|
||||
// 获取真实用户信息
|
||||
try {
|
||||
final user = await _authService.getUserInfo();
|
||||
state = state.copyWith(
|
||||
user: user,
|
||||
isAuthenticated: true,
|
||||
);
|
||||
} catch (e) {
|
||||
// Token可能已过期,清除token
|
||||
await _storageService.clearTokens();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略错误,保持未认证状态
|
||||
}
|
||||
}
|
||||
|
||||
/// 登录
|
||||
Future<void> login({
|
||||
required String account, // 用户名或邮箱
|
||||
required String password,
|
||||
bool rememberMe = false,
|
||||
}) async {
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
try {
|
||||
// 调用真实API
|
||||
final authResponse = await _authService.login(
|
||||
account: account,
|
||||
password: password,
|
||||
rememberMe: rememberMe,
|
||||
);
|
||||
|
||||
// 保存token
|
||||
await _storageService.saveToken(authResponse.token);
|
||||
if (rememberMe && authResponse.refreshToken != null) {
|
||||
await _storageService.saveRefreshToken(authResponse.refreshToken!);
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
state = state.copyWith(
|
||||
user: authResponse.user,
|
||||
isAuthenticated: true,
|
||||
isLoading: false,
|
||||
);
|
||||
} catch (e) {
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
error: e.toString(),
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 注册
|
||||
Future<void> register({
|
||||
required String email,
|
||||
required String password,
|
||||
required String username,
|
||||
required String nickname,
|
||||
}) async {
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
try {
|
||||
// 调用真实API
|
||||
final authResponse = await _authService.register(
|
||||
email: email,
|
||||
password: password,
|
||||
username: username,
|
||||
nickname: nickname,
|
||||
);
|
||||
|
||||
// 保存token
|
||||
await _storageService.saveToken(authResponse.token);
|
||||
if (authResponse.refreshToken != null) {
|
||||
await _storageService.saveRefreshToken(authResponse.refreshToken!);
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
state = state.copyWith(
|
||||
user: authResponse.user,
|
||||
isAuthenticated: true,
|
||||
isLoading: false,
|
||||
);
|
||||
} catch (e) {
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
error: e.toString(),
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 登出
|
||||
Future<void> logout() async {
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
try {
|
||||
// 模拟网络延迟
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
await _storageService.clearTokens();
|
||||
|
||||
state = const AuthState();
|
||||
} catch (e) {
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
error: e.toString(),
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 忘记密码
|
||||
Future<void> forgotPassword(String email) async {
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
try {
|
||||
// 模拟网络延迟
|
||||
await Future.delayed(const Duration(milliseconds: 1000));
|
||||
|
||||
if (email.isEmpty) {
|
||||
throw Exception('邮箱地址不能为空');
|
||||
}
|
||||
|
||||
// 模拟发送重置邮件成功
|
||||
state = state.copyWith(isLoading: false);
|
||||
} catch (e) {
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
error: e.toString(),
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 重置密码
|
||||
Future<void> resetPassword({
|
||||
required String token,
|
||||
required String newPassword,
|
||||
}) async {
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
try {
|
||||
// 模拟网络延迟
|
||||
await Future.delayed(const Duration(milliseconds: 1000));
|
||||
|
||||
if (newPassword.length < 6) {
|
||||
throw Exception('密码长度不能少于6位');
|
||||
}
|
||||
|
||||
state = state.copyWith(isLoading: false);
|
||||
} catch (e) {
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
error: e.toString(),
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 更新用户信息
|
||||
Future<void> updateProfile({
|
||||
String? username,
|
||||
String? email,
|
||||
String? phone,
|
||||
String? avatar,
|
||||
}) async {
|
||||
if (state.user == null) return;
|
||||
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
try {
|
||||
// 模拟网络延迟
|
||||
await Future.delayed(const Duration(milliseconds: 1000));
|
||||
|
||||
final updatedUser = state.user!.copyWith(
|
||||
username: username ?? state.user!.username,
|
||||
email: email ?? state.user!.email,
|
||||
phone: phone ?? state.user!.phone,
|
||||
avatar: avatar ?? state.user!.avatar,
|
||||
updatedAt: DateTime.now(),
|
||||
);
|
||||
|
||||
state = state.copyWith(
|
||||
user: updatedUser,
|
||||
isLoading: false,
|
||||
);
|
||||
} catch (e) {
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
error: e.toString(),
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 修改密码
|
||||
Future<void> changePassword({
|
||||
required String currentPassword,
|
||||
required String newPassword,
|
||||
}) async {
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
try {
|
||||
// 模拟网络延迟
|
||||
await Future.delayed(const Duration(milliseconds: 1000));
|
||||
|
||||
if (currentPassword.isEmpty || newPassword.isEmpty) {
|
||||
throw Exception('当前密码和新密码不能为空');
|
||||
}
|
||||
|
||||
if (newPassword.length < 6) {
|
||||
throw Exception('新密码长度不能少于6位');
|
||||
}
|
||||
|
||||
state = state.copyWith(isLoading: false);
|
||||
} catch (e) {
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
error: e.toString(),
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 清除错误
|
||||
void clearError() {
|
||||
state = state.copyWith(error: null);
|
||||
}
|
||||
}
|
||||
|
||||
/// 认证服务提供者
|
||||
final authServiceProvider = Provider<AuthService>((ref) {
|
||||
return AuthService(ApiClient.instance);
|
||||
});
|
||||
|
||||
/// 存储服务提供者 - 改为同步Provider,因为StorageService已在main中初始化
|
||||
final storageServiceProvider = Provider<StorageService>((ref) {
|
||||
// StorageService已经在main.dart中初始化,直接获取实例
|
||||
// 这里使用一个技巧:通过Future.value包装已初始化的实例
|
||||
throw UnimplementedError('Use storageServiceInstanceProvider instead');
|
||||
});
|
||||
|
||||
/// 认证状态提供者 - 改为StateNotifierProvider以保持状态
|
||||
final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
|
||||
final authService = ref.watch(authServiceProvider);
|
||||
// 直接使用已初始化的StorageService实例
|
||||
final storageService = StorageService.instance;
|
||||
|
||||
return AuthNotifier(authService, storageService);
|
||||
});
|
||||
|
||||
/// 是否已认证的提供者
|
||||
final isAuthenticatedProvider = Provider<bool>((ref) {
|
||||
return ref.watch(authProvider).isAuthenticated;
|
||||
});
|
||||
|
||||
/// 当前用户提供者
|
||||
final currentUserProvider = Provider<User?>((ref) {
|
||||
return ref.watch(authProvider).user;
|
||||
});
|
||||
Reference in New Issue
Block a user