forked from eatvio/eatvio_app
feat(auth): Issue-691
This commit is contained in:
@@ -389,63 +389,46 @@ class _SocialButton extends StatelessWidget {
|
||||
}
|
||||
|
||||
void _onVkPressed(BuildContext context) async {
|
||||
print('[VK] VK button pressed');
|
||||
try {
|
||||
final accessToken = await SocialAuthFacade.signInWithVk(context: context);
|
||||
print('[VK] Got access token: ${accessToken != null ? 'success' : 'null'}');
|
||||
if (accessToken == null) {
|
||||
print('[VK] No access token received');
|
||||
return;
|
||||
}
|
||||
final isAuthenticated = await sl<AuthCubit>().getTokenBySocial(provider: 'vk', accessToken: accessToken);
|
||||
print('[VK] Authentication result: $isAuthenticated');
|
||||
if (isAuthenticated) {
|
||||
if (AppRouter.navigatorKey.currentContext != null) {
|
||||
// Reuse success flow
|
||||
// ignore: use_build_context_synchronously
|
||||
await _reconnectAfterAuth();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('[VK] Error during VK auth: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void _onOkPressed() async {
|
||||
print('[OK] OK button pressed');
|
||||
try {
|
||||
final accessToken = await SocialAuthFacade.signInWithOk();
|
||||
print('[OK] Got access token: ${accessToken != null ? 'success' : 'null'}');
|
||||
if (accessToken == null) {
|
||||
print('[OK] No access token received');
|
||||
return;
|
||||
}
|
||||
final isAuthenticated = await sl<AuthCubit>().getTokenBySocial(provider: 'ok', accessToken: accessToken);
|
||||
print('[OK] Authentication result: $isAuthenticated');
|
||||
if (isAuthenticated) {
|
||||
await _reconnectAfterAuth();
|
||||
}
|
||||
} catch (e) {
|
||||
print('[OK] Error during OK auth: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void _onMailRuPressed() async {
|
||||
print('[MailRu] MailRu button pressed');
|
||||
try {
|
||||
final accessToken = await SocialAuthFacade.signInWithMailRu();
|
||||
print('[MailRu] Got access token: ${accessToken != null ? 'success' : 'null'}');
|
||||
if (accessToken == null) {
|
||||
print('[MailRu] No access token received');
|
||||
return;
|
||||
}
|
||||
final isAuthenticated = await sl<AuthCubit>().getTokenBySocial(provider: 'mailru', accessToken: accessToken);
|
||||
print('[MailRu] Authentication result: $isAuthenticated');
|
||||
if (isAuthenticated) {
|
||||
await _reconnectAfterAuth();
|
||||
}
|
||||
} catch (e) {
|
||||
print('[MailRu] Error during MailRu auth: $e');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,51 +29,35 @@ class SocialAuthFacade {
|
||||
|
||||
static Future<VkAuthResult?> signInWithVkAndFetchProfile({required BuildContext context}) async {
|
||||
final clientIdStr = EnvConfig.vkClientId.trim();
|
||||
print('[VK] VK_CLIENT_ID from EnvConfig: $clientIdStr');
|
||||
if (clientIdStr.isEmpty) {
|
||||
print('[VK] VK_CLIENT_ID is not set. Configure it in .env');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
print('[VK] Creating VkIDController with clientId: $clientIdStr');
|
||||
dynamic controller = VkIDController(clID: int.parse(clientIdStr));
|
||||
final authUri = controller.generateAuthorizeLinkWithCodeVerifier();
|
||||
print('[VK] Generated auth URI: $authUri');
|
||||
|
||||
// Extract URL from MapEntry
|
||||
String authUrl;
|
||||
if (authUri is MapEntry) {
|
||||
authUrl = authUri.value.toString();
|
||||
} else {
|
||||
authUrl = authUri.toString();
|
||||
}
|
||||
print('[VK] Extracted auth URL: $authUrl');
|
||||
|
||||
final redirectScheme = 'vk$clientIdStr://';
|
||||
print('[VK] Redirect scheme: $redirectScheme');
|
||||
|
||||
final redirectParams = await _presentOAuthWebView(context: context, initialUrl: authUrl, redirectSchemePrefix: redirectScheme);
|
||||
print('[VK] WebView returned params: $redirectParams');
|
||||
if (redirectParams == null) {
|
||||
print('[VK] No redirect params received');
|
||||
return null;
|
||||
}
|
||||
|
||||
final code = redirectParams['code'];
|
||||
final deviceId = redirectParams['device_id'];
|
||||
print('[VK] Code: $code, DeviceId: $deviceId');
|
||||
if (code == null || deviceId == null) {
|
||||
print('[VK] Missing code or deviceId');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Instead of exchanging the code on-device (the sdk method is not available),
|
||||
// return the authorization code so the backend can exchange it securely.
|
||||
print('[VK] Returning authorization code to backend for exchange');
|
||||
return VkAuthResult(accessToken: code);
|
||||
} catch (e) {
|
||||
print('[VK] Error in signInWithVkAndFetchProfile: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -94,20 +78,47 @@ class SocialAuthFacade {
|
||||
final clientId = EnvConfig.yandexClientId.trim();
|
||||
final redirectUri = EnvConfig.yandexRedirectUri.trim();
|
||||
|
||||
print('[Yandex] Client ID: $clientId');
|
||||
print('[Yandex] Redirect URI: $redirectUri');
|
||||
|
||||
if (clientId.isEmpty || redirectUri.isEmpty) {
|
||||
print('[Yandex] Missing YANDEX_CLIENT_ID or YANDEX_REDIRECT_URI in .env');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final plugin = FlutterLoginYandex();
|
||||
final response = await plugin.signIn();
|
||||
final token = (response is Map) ? response['token'] as String? : null;
|
||||
return (token != null && token.isNotEmpty) ? token : null;
|
||||
} catch (_) {
|
||||
final context = AppRouter.navigatorKey.currentContext;
|
||||
if (context == null) return null;
|
||||
|
||||
final authorizeUrl = Uri.https('oauth.yandex.ru', '/authorize', {
|
||||
'response_type': 'token',
|
||||
'client_id': clientId,
|
||||
'redirect_uri': redirectUri,
|
||||
'force_confirm': 'yes',
|
||||
}).toString();
|
||||
|
||||
final redirectSchemePrefix = redirectUri;
|
||||
|
||||
final params = await _presentOAuthWebView(context: context, initialUrl: authorizeUrl, redirectSchemePrefix: redirectSchemePrefix);
|
||||
|
||||
if (params == null) return null;
|
||||
|
||||
final token = params['access_token'];
|
||||
if (token != null && token.isNotEmpty) {
|
||||
return token;
|
||||
}
|
||||
|
||||
final code = params['code'];
|
||||
if (code != null && code.isNotEmpty) {
|
||||
return code;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
try {
|
||||
final plugin = FlutterLoginYandex();
|
||||
final response = await plugin.signIn();
|
||||
final token = (response is Map) ? response['token'] as String? : null;
|
||||
return (token != null && token.isNotEmpty) ? token : null;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,26 +128,16 @@ class SocialAuthFacade {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
print('[VK] Provider flow start: $provider, clientId: $clientIdStr');
|
||||
dynamic controller = VkIDController(clID: int.parse(clientIdStr));
|
||||
|
||||
// Try different approaches for provider parameter
|
||||
dynamic authUri;
|
||||
try {
|
||||
// First try with provider as string
|
||||
authUri = controller.generateAuthorizeLinkWithCodeVerifier(provider: provider);
|
||||
print('[VK] [$provider] Generated auth URI with string provider: $authUri');
|
||||
} catch (e) {
|
||||
print('[VK] [$provider] Failed with string provider, trying null: $e');
|
||||
try {
|
||||
// Try with null provider
|
||||
authUri = controller.generateAuthorizeLinkWithCodeVerifier(provider: null);
|
||||
print('[VK] [$provider] Generated auth URI with null provider: $authUri');
|
||||
} catch (e2) {
|
||||
print('[VK] [$provider] Failed with null provider, trying without provider: $e2');
|
||||
// Try without provider parameter
|
||||
authUri = controller.generateAuthorizeLinkWithCodeVerifier();
|
||||
print('[VK] [$provider] Generated auth URI without provider: $authUri');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,61 +148,53 @@ class SocialAuthFacade {
|
||||
} else {
|
||||
authUrl = authUri.toString();
|
||||
}
|
||||
print('[VK] [$provider] Extracted auth URL: $authUrl');
|
||||
|
||||
final redirectScheme = 'vk$clientIdStr://';
|
||||
print('[VK] [$provider] Redirect scheme: $redirectScheme');
|
||||
final redirectParams = await _presentOAuthWebView(context: context, initialUrl: authUrl, redirectSchemePrefix: redirectScheme);
|
||||
print('[VK] [$provider] WebView returned params: $redirectParams');
|
||||
if (redirectParams == null) return null;
|
||||
final code = redirectParams['code'];
|
||||
final deviceId = redirectParams['device_id'];
|
||||
print('[VK] [$provider] Code: $code, DeviceId: $deviceId');
|
||||
if (code == null || deviceId == null) return null;
|
||||
// Return the authorization code to be exchanged by the backend for provider flow
|
||||
return code;
|
||||
} catch (e) {
|
||||
print('[VK] [$provider] Error in provider flow: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Token extraction is no longer needed because we return the authorization code
|
||||
// to the backend for exchange.
|
||||
|
||||
static Future<Map<String, String>?> _presentOAuthWebView({
|
||||
required BuildContext context,
|
||||
required String initialUrl,
|
||||
required String redirectSchemePrefix,
|
||||
}) async {
|
||||
print('[VK] WebView: Loading URL: $initialUrl');
|
||||
print('[VK] WebView: Redirect scheme: $redirectSchemePrefix');
|
||||
|
||||
final controller = WebViewController()
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
..setNavigationDelegate(
|
||||
NavigationDelegate(
|
||||
onNavigationRequest: (request) {
|
||||
final url = request.url;
|
||||
print('[VK] WebView: Navigation to: $url');
|
||||
if (url.startsWith(redirectSchemePrefix)) {
|
||||
print('[VK] WebView: Redirect detected, parsing params');
|
||||
final uri = Uri.parse(url);
|
||||
final params = <String, String>{}..addAll(uri.queryParameters);
|
||||
print('[VK] WebView: Parsed params: $params');
|
||||
if (uri.fragment.isNotEmpty) {
|
||||
final fragPairs = uri.fragment.split('&');
|
||||
for (final pair in fragPairs) {
|
||||
final eq = pair.indexOf('=');
|
||||
if (eq > 0 && eq < pair.length - 1) {
|
||||
final key = Uri.decodeComponent(pair.substring(0, eq));
|
||||
final value = Uri.decodeComponent(pair.substring(eq + 1));
|
||||
params[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Navigator.of(context, rootNavigator: true).pop(params);
|
||||
return NavigationDecision.prevent;
|
||||
}
|
||||
return NavigationDecision.navigate;
|
||||
},
|
||||
onPageStarted: (url) {
|
||||
print('[VK] WebView: Page started loading: $url');
|
||||
},
|
||||
onPageFinished: (url) {
|
||||
print('[VK] WebView: Page finished loading: $url');
|
||||
},
|
||||
onWebResourceError: (error) {
|
||||
print('[VK] WebView: Error: ${error.description}');
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -209,7 +202,6 @@ class SocialAuthFacade {
|
||||
try {
|
||||
await controller.loadRequest(Uri.parse(initialUrl));
|
||||
} catch (e) {
|
||||
print('[VK] WebView: Failed to load URL: $e');
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,6 @@ Future<void> main() async {
|
||||
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
||||
|
||||
await dotenv.load(fileName: ".env");
|
||||
print('[ENV] Loaded .env file');
|
||||
print('[ENV] VK_CLIENT_ID: ${dotenv.maybeGet('VK_CLIENT_ID')}');
|
||||
|
||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||
await FirebaseMessaging.instance.requestPermission();
|
||||
|
||||
Reference in New Issue
Block a user