103 lines
3.3 KiB
Dart
103 lines
3.3 KiB
Dart
import 'dart:convert' show base64, utf8;
|
|
import 'dart:convert' show jsonDecode, jsonEncode;
|
|
|
|
import 'package:fotodocumentation/controller/base_controller.dart';
|
|
import 'package:fotodocumentation/dto/jwt_token_pair_dto.dart';
|
|
import 'package:fotodocumentation/main.dart' show logger;
|
|
import 'package:fotodocumentation/utils/di_container.dart';
|
|
import 'package:fotodocumentation/utils/jwt_token_storage.dart';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
typedef AuthenticateReply = ({JwtTokenPairDto? jwtTokenPairDto});
|
|
|
|
abstract interface class LoginController {
|
|
Future<AuthenticateReply> authenticate(String username, String password);
|
|
Future<bool> refreshAccessToken();
|
|
bool isUsingJwtAuth();
|
|
}
|
|
|
|
class LoginControllerImpl extends BaseController implements LoginController {
|
|
final String path = "login";
|
|
|
|
JwtTokenStorage get _jwtTokenStorage => DiContainer.get();
|
|
|
|
@override
|
|
Future<AuthenticateReply> authenticate(String username, String password) async {
|
|
http.Client client = httpClientUtils.client;
|
|
try {
|
|
Header cred = _getLoginHeader(username, password);
|
|
String uriStr = '${uriUtils.getBaseUrl()}$path';
|
|
Uri uri = Uri.parse(uriStr);
|
|
|
|
var response = await client.get(uri, headers: {cred.name: cred.value});
|
|
if (response.statusCode == 200) {
|
|
final Map<String, dynamic> data = Map.castFrom(jsonDecode(response.body));
|
|
|
|
final tokenPair = JwtTokenPairDto.fromJson(data);
|
|
|
|
// Store tokens securely
|
|
_jwtTokenStorage.saveTokens(tokenPair.accessToken, tokenPair.refreshToken);
|
|
|
|
// Load user data using the new token
|
|
return (jwtTokenPairDto: tokenPair);
|
|
} else {
|
|
logger.e('Authentication failed: ${response.statusCode} ${response.body}');
|
|
return (jwtTokenPairDto: null);
|
|
}
|
|
} catch (e) {
|
|
logger.e("Authentication error: $e");
|
|
return (jwtTokenPairDto: null);
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<bool> refreshAccessToken() async {
|
|
try {
|
|
final refreshToken = _jwtTokenStorage.getRefreshToken();
|
|
if (refreshToken == null) {
|
|
logger.i('No refresh token available');
|
|
return false;
|
|
}
|
|
String uriStr = '${uriUtils.getBaseUrl()}$path/login/refresh';
|
|
Uri uri = Uri.parse(uriStr);
|
|
|
|
final response = await http.post(
|
|
uri,
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({
|
|
'refreshToken': refreshToken,
|
|
}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final data = jsonDecode(response.body);
|
|
final newAccessToken = data['accessToken'] as String;
|
|
|
|
// Update only the access token (keep same refresh token)
|
|
_jwtTokenStorage.updateAccessToken(newAccessToken);
|
|
|
|
logger.d('Access token refreshed successfully');
|
|
return true;
|
|
} else {
|
|
logger.d('Token refresh failed: ${response.statusCode} ${response.body}');
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
logger.e('Token refresh error: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool isUsingJwtAuth() {
|
|
return _jwtTokenStorage.hasTokens();
|
|
}
|
|
|
|
Header _getLoginHeader(String username, String password) {
|
|
String combined = "$username:$password";
|
|
final bytes = utf8.encode(combined);
|
|
String asBase64 = base64.encode(bytes);
|
|
return Header("Authorization", "Basic $asBase64");
|
|
}
|
|
}
|