😋 初始化仓库
This commit is contained in:
273
lib/providers/auth_provider.dart
Normal file
273
lib/providers/auth_provider.dart
Normal file
@@ -0,0 +1,273 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../models/user_credentials.dart';
|
||||
import '../services/aufe_connection.dart';
|
||||
|
||||
/// Authentication state enum
|
||||
enum AuthState { initial, loading, authenticated, unauthenticated, error }
|
||||
|
||||
/// Provider for managing authentication state and user sessions
|
||||
///
|
||||
/// Handles login, logout, session checking, and credential management
|
||||
/// Uses ChangeNotifier to notify listeners of state changes
|
||||
///
|
||||
/// Usage example:
|
||||
/// ```dart
|
||||
/// final authProvider = Provider.of<AuthProvider>(context);
|
||||
///
|
||||
/// // Login
|
||||
/// await authProvider.login(
|
||||
/// userId: '学号',
|
||||
/// ecPassword: 'EC密码',
|
||||
/// password: 'UAAP密码',
|
||||
/// );
|
||||
///
|
||||
/// // Check session
|
||||
/// final isValid = await authProvider.checkSession();
|
||||
///
|
||||
/// // Logout
|
||||
/// await authProvider.logout();
|
||||
/// ```
|
||||
class AuthProvider extends ChangeNotifier {
|
||||
AUFEConnection? _connection;
|
||||
AuthState _state = AuthState.initial;
|
||||
String? _errorMessage;
|
||||
UserCredentials? _credentials;
|
||||
|
||||
/// Get current authentication state
|
||||
AuthState get state => _state;
|
||||
|
||||
/// Get current error message (if any)
|
||||
String? get errorMessage => _errorMessage;
|
||||
|
||||
/// Get current connection instance
|
||||
AUFEConnection? get connection => _connection;
|
||||
|
||||
/// Get current user credentials
|
||||
UserCredentials? get credentials => _credentials;
|
||||
|
||||
/// Check if user is authenticated
|
||||
bool get isAuthenticated => _state == AuthState.authenticated;
|
||||
|
||||
/// Login with user credentials
|
||||
///
|
||||
/// Creates AUFEConnection and performs both EC and UAAP login
|
||||
/// Saves credentials securely on successful login
|
||||
///
|
||||
/// [userId] - Student ID
|
||||
/// [ecPassword] - EC system password
|
||||
/// [password] - UAAP system password
|
||||
///
|
||||
/// Returns true if login succeeds, false otherwise
|
||||
Future<bool> login({
|
||||
required String userId,
|
||||
required String ecPassword,
|
||||
required String password,
|
||||
}) async {
|
||||
try {
|
||||
print('🔐 Starting login process...');
|
||||
print('🔐 User ID: $userId');
|
||||
|
||||
_setState(AuthState.loading);
|
||||
_errorMessage = null;
|
||||
|
||||
// Create credentials
|
||||
final credentials = UserCredentials(
|
||||
userId: userId,
|
||||
ecPassword: ecPassword,
|
||||
password: password,
|
||||
);
|
||||
|
||||
// Create connection
|
||||
print('🔐 Creating AUFEConnection...');
|
||||
final connection = AUFEConnection(
|
||||
userId: userId,
|
||||
ecPassword: ecPassword,
|
||||
password: password,
|
||||
);
|
||||
|
||||
// Initialize HTTP client
|
||||
print('🔐 Starting HTTP client...');
|
||||
connection.startClient();
|
||||
|
||||
// Perform EC login
|
||||
print('🔐 Performing EC login...');
|
||||
final ecLoginStatus = await connection.ecLogin();
|
||||
print('🔐 EC login result: ${ecLoginStatus.success}');
|
||||
|
||||
if (!ecLoginStatus.success) {
|
||||
_errorMessage = _getEcLoginErrorMessage(ecLoginStatus);
|
||||
print('❌ EC login failed: $_errorMessage');
|
||||
_setState(AuthState.error);
|
||||
await connection.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Perform UAAP login
|
||||
print('🔐 Performing UAAP login...');
|
||||
final uaapLoginStatus = await connection.uaapLogin();
|
||||
print('🔐 UAAP login result: ${uaapLoginStatus.success}');
|
||||
|
||||
if (!uaapLoginStatus.success) {
|
||||
_errorMessage = _getUaapLoginErrorMessage(uaapLoginStatus);
|
||||
print('❌ UAAP login failed: $_errorMessage');
|
||||
_setState(AuthState.error);
|
||||
await connection.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save credentials securely
|
||||
print('🔐 Saving credentials...');
|
||||
await credentials.saveSecurely();
|
||||
|
||||
// Update state
|
||||
_connection = connection;
|
||||
_credentials = credentials;
|
||||
_setState(AuthState.authenticated);
|
||||
|
||||
print('✅ Login successful!');
|
||||
return true;
|
||||
} catch (e, stackTrace) {
|
||||
_errorMessage = '登录过程出错: $e';
|
||||
print('❌ Login error: $e');
|
||||
print('❌ Stack trace: $stackTrace');
|
||||
_setState(AuthState.error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Logout and clear all session data
|
||||
///
|
||||
/// Closes connection, clears credentials from secure storage,
|
||||
/// and resets authentication state
|
||||
Future<void> logout() async {
|
||||
try {
|
||||
// Close connection
|
||||
if (_connection != null) {
|
||||
await _connection!.close();
|
||||
_connection = null;
|
||||
}
|
||||
|
||||
// Clear credentials from secure storage
|
||||
await UserCredentials.clearSecurely();
|
||||
|
||||
// Reset state
|
||||
_credentials = null;
|
||||
_errorMessage = null;
|
||||
_setState(AuthState.unauthenticated);
|
||||
} catch (e) {
|
||||
debugPrint('Error during logout: $e');
|
||||
// Still reset state even if cleanup fails
|
||||
_connection = null;
|
||||
_credentials = null;
|
||||
_setState(AuthState.unauthenticated);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if current session is still valid
|
||||
///
|
||||
/// Performs health check on the connection
|
||||
/// If session is invalid, updates state to unauthenticated
|
||||
///
|
||||
/// Returns true if session is valid, false otherwise
|
||||
Future<bool> checkSession() async {
|
||||
if (_connection == null || _state != AuthState.authenticated) {
|
||||
_setState(AuthState.unauthenticated);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final isHealthy = await _connection!.healthCheck();
|
||||
|
||||
if (!isHealthy) {
|
||||
_errorMessage = '会话已过期,请重新登录';
|
||||
_setState(AuthState.unauthenticated);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
_errorMessage = '检查会话状态失败: $e';
|
||||
_setState(AuthState.error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to restore session from saved credentials
|
||||
///
|
||||
/// Loads credentials from secure storage and attempts to login
|
||||
/// Useful for auto-login on app startup
|
||||
///
|
||||
/// Returns true if session restored successfully, false otherwise
|
||||
Future<bool> restoreSession() async {
|
||||
try {
|
||||
_setState(AuthState.loading);
|
||||
|
||||
// Load saved credentials
|
||||
final credentials = await UserCredentials.loadSecurely();
|
||||
if (credentials == null) {
|
||||
_setState(AuthState.unauthenticated);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt login with saved credentials
|
||||
return await login(
|
||||
userId: credentials.userId,
|
||||
ecPassword: credentials.ecPassword,
|
||||
password: credentials.password,
|
||||
);
|
||||
} catch (e) {
|
||||
_errorMessage = '恢复会话失败: $e';
|
||||
_setState(AuthState.unauthenticated);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Update authentication state and notify listeners
|
||||
void _setState(AuthState newState) {
|
||||
_state = newState;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Get user-friendly error message for EC login status
|
||||
String _getEcLoginErrorMessage(dynamic status) {
|
||||
if (status.failInvalidCredentials) {
|
||||
return 'EC系统用户名或密码错误';
|
||||
} else if (status.failNotFoundTwfid) {
|
||||
return '无法获取TwfID,请稍后重试';
|
||||
} else if (status.failNotFoundRsaKey) {
|
||||
return '无法获取RSA密钥,请稍后重试';
|
||||
} else if (status.failNotFoundRsaExp) {
|
||||
return '无法获取RSA指数,请稍后重试';
|
||||
} else if (status.failNotFoundCsrfCode) {
|
||||
return '无法获取CSRF代码,请稍后重试';
|
||||
} else if (status.failMaybeAttacked) {
|
||||
return '登录频繁,请稍后重试';
|
||||
} else if (status.failNetworkError) {
|
||||
return 'EC系统网络连接失败';
|
||||
} else {
|
||||
return 'EC系统登录失败';
|
||||
}
|
||||
}
|
||||
|
||||
/// Get user-friendly error message for UAAP login status
|
||||
String _getUaapLoginErrorMessage(dynamic status) {
|
||||
if (status.failInvalidCredentials) {
|
||||
return 'UAAP系统用户名或密码错误';
|
||||
} else if (status.failNotFoundLt) {
|
||||
return '无法获取lt参数,请稍后重试';
|
||||
} else if (status.failNotFoundExecution) {
|
||||
return '无法获取execution参数,请稍后重试';
|
||||
} else if (status.failNetworkError) {
|
||||
return 'UAAP系统网络连接失败';
|
||||
} else {
|
||||
return 'UAAP系统登录失败';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Close connection when provider is disposed
|
||||
_connection?.close();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user