- 在本地化文件中添加认证相关的多语言支持 - 实现密码验证逻辑和锁定机制 - 创建登录页面UI组件 - 集成路由保护,未认证用户自动重定向到登录页 - 支持密码错误次数限制和倒计时锁定功能
99 lines
2.4 KiB
Dart
99 lines
2.4 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../../settings/services/settings_service.dart';
|
|
|
|
/// 认证状态枚举
|
|
enum AuthStatus { unauthenticated, authenticated }
|
|
|
|
/// 认证状态数据
|
|
class AuthState {
|
|
final AuthStatus status;
|
|
final int remainingAttempts;
|
|
final DateTime? lockUntil;
|
|
|
|
const AuthState({
|
|
this.status = AuthStatus.unauthenticated,
|
|
this.remainingAttempts = 5,
|
|
this.lockUntil,
|
|
});
|
|
|
|
bool get isLocked => lockUntil != null && DateTime.now().isBefore(lockUntil!);
|
|
|
|
int get lockSecondsRemaining {
|
|
if (lockUntil == null) return 0;
|
|
final diff = lockUntil!.difference(DateTime.now()).inSeconds;
|
|
return diff > 0 ? diff : 0;
|
|
}
|
|
|
|
AuthState copyWith({
|
|
AuthStatus? status,
|
|
int? remainingAttempts,
|
|
DateTime? Function()? lockUntil,
|
|
}) {
|
|
return AuthState(
|
|
status: status ?? this.status,
|
|
remainingAttempts: remainingAttempts ?? this.remainingAttempts,
|
|
lockUntil: lockUntil != null ? lockUntil() : this.lockUntil,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 认证状态管理器
|
|
class AuthNotifier extends StateNotifier<AuthState> {
|
|
AuthNotifier() : super(const AuthState());
|
|
|
|
static const maxAttempts = 5;
|
|
static const lockDuration = Duration(seconds: 30);
|
|
|
|
/// 验证密码
|
|
Future<bool> verify(String password) async {
|
|
if (state.isLocked) {
|
|
return false;
|
|
}
|
|
|
|
final isValid = await SettingsService.instance.verifyPassword(password);
|
|
|
|
if (isValid) {
|
|
state = const AuthState(status: AuthStatus.authenticated);
|
|
return true;
|
|
}
|
|
|
|
final newAttempts = state.remainingAttempts - 1;
|
|
|
|
if (newAttempts <= 0) {
|
|
state = state.copyWith(
|
|
remainingAttempts: 0,
|
|
lockUntil: () => DateTime.now().add(lockDuration),
|
|
);
|
|
_startLockTimer();
|
|
} else {
|
|
state = state.copyWith(remainingAttempts: newAttempts);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// 锁定倒计时结束后自动解锁
|
|
void _startLockTimer() {
|
|
Timer(lockDuration, () {
|
|
if (state.status == AuthStatus.authenticated) return;
|
|
state = AuthState(
|
|
status: state.status,
|
|
remainingAttempts: maxAttempts,
|
|
lockUntil: null,
|
|
);
|
|
});
|
|
}
|
|
|
|
/// 重置认证状态(用于登出)
|
|
void reset() {
|
|
state = const AuthState();
|
|
}
|
|
}
|
|
|
|
final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
|
|
return AuthNotifier();
|
|
});
|