feat(auth): 添加启动认证功能
- 在本地化文件中添加认证相关的多语言支持 - 实现密码验证逻辑和锁定机制 - 创建登录页面UI组件 - 集成路由保护,未认证用户自动重定向到登录页 - 支持密码错误次数限制和倒计时锁定功能
This commit is contained in:
98
lib/features/auth/providers/auth_provider.dart
Normal file
98
lib/features/auth/providers/auth_provider.dart
Normal file
@@ -0,0 +1,98 @@
|
||||
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();
|
||||
});
|
||||
Reference in New Issue
Block a user