migrated timetable integration from WebUntis to the MarianumConnect API, implementing a Dio-based client with bearer token authentication, background session validation, and auto-refresh logic.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../../../errors/auth_exception.dart';
|
||||
import '../../auth/token_storage.dart';
|
||||
import '../../errors/marianumconnect_error.dart';
|
||||
import '../../marianumconnect_endpoint.dart';
|
||||
|
||||
/// Probes that the stored bearer token still maps to the given credentials.
|
||||
/// Server returns 200 only when the credentials belong to the user that the
|
||||
/// token was issued for — a password rotation on that user's account flips
|
||||
/// it to 401 even if the token itself would still be accepted.
|
||||
///
|
||||
/// Bypasses the shared dio singleton so the auth interceptor doesn't kick in
|
||||
/// and obscure a real 401 with a silent re-login.
|
||||
class AuthVerify {
|
||||
static const Duration _connectTimeout = Duration(seconds: 10);
|
||||
static const Duration _receiveTimeout = Duration(seconds: 15);
|
||||
|
||||
final MarianumConnectTokenStorage _tokenStorage;
|
||||
final Dio _dio;
|
||||
|
||||
AuthVerify({
|
||||
MarianumConnectTokenStorage tokenStorage =
|
||||
const MarianumConnectTokenStorage(),
|
||||
Dio? dio,
|
||||
}) : _tokenStorage = tokenStorage,
|
||||
_dio =
|
||||
dio ??
|
||||
Dio(
|
||||
BaseOptions(
|
||||
connectTimeout: _connectTimeout,
|
||||
sendTimeout: _connectTimeout,
|
||||
receiveTimeout: _receiveTimeout,
|
||||
responseType: ResponseType.json,
|
||||
contentType: 'application/json',
|
||||
),
|
||||
);
|
||||
|
||||
/// Throws [AuthException] on 401 (credentials no longer match the token's
|
||||
/// user, token missing, or token rejected), other [AppException]s on
|
||||
/// network/server errors. Completes silently on success.
|
||||
Future<void> run({
|
||||
required String username,
|
||||
required String password,
|
||||
}) async {
|
||||
final token = await _tokenStorage.readToken();
|
||||
if (token == null || token.isEmpty) {
|
||||
throw AuthException.unauthorized(
|
||||
technicalDetails: 'AuthVerify: no bearer token in storage',
|
||||
);
|
||||
}
|
||||
try {
|
||||
await _dio.post<void>(
|
||||
MarianumConnectEndpoint.resolve('auth/verify'),
|
||||
data: {'username': username, 'password': password},
|
||||
options: Options(headers: {'Authorization': 'Bearer $token'}),
|
||||
);
|
||||
} on DioException catch (e) {
|
||||
throw mapMarianumConnectError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user