forked from baron/baron-sso
flutter 린트 적용
This commit is contained in:
@@ -88,3 +88,16 @@ String buildLocalizedPath(String localeCode, Uri uri) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String buildSigninRedirectPath(String localeCode, Uri uri) {
|
||||
final newPath = '/$localeCode/signin';
|
||||
final newUri = uri.replace(path: newPath);
|
||||
String result = newUri.path;
|
||||
if (newUri.hasQuery) {
|
||||
result += '?${newUri.query}';
|
||||
}
|
||||
if (newUri.hasFragment) {
|
||||
result += '#${newUri.fragment}';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class AuthTokenStore {
|
||||
_localStorage.setItem(_providerKey, provider);
|
||||
}
|
||||
} catch (e) {
|
||||
print("[AuthTokenStore] CRITICAL - Failed to set token: $e");
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,25 +12,17 @@ class WebWindow {
|
||||
|
||||
void redirectTo(String url) {
|
||||
final currentHref = web.window.location.href;
|
||||
Uri? targetUri;
|
||||
try {
|
||||
targetUri = Uri.parse(url);
|
||||
} catch (_) {
|
||||
debugPrint("[WebWindow] redirectTo parse failed: url=$url");
|
||||
}
|
||||
|
||||
debugPrint(
|
||||
"[WebWindow] redirectTo start: current=$currentHref, target=$url",
|
||||
);
|
||||
|
||||
print("[WebWindow] FINAL REDIRECT ATTEMPT. URL: $url");
|
||||
|
||||
// Most direct and safe way for WASM: location.href assignment via package:web
|
||||
Future.delayed(Duration.zero, () {
|
||||
try {
|
||||
web.window.location.href = url;
|
||||
} catch (e) {
|
||||
print("[WebWindow] CRITICAL JS ERROR: $e");
|
||||
debugPrint("[WebWindow] CRITICAL JS ERROR: $e");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -38,11 +38,10 @@ class LanguageSelector extends StatelessWidget {
|
||||
}
|
||||
LocaleStorage.write(value);
|
||||
await context.setLocale(Locale(value));
|
||||
if (!context.mounted) return;
|
||||
final uri = GoRouterState.of(context).uri;
|
||||
final target = buildLocalizedPath(value, uri);
|
||||
if (context.mounted) {
|
||||
context.go(target);
|
||||
}
|
||||
context.go(target);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -12,7 +12,6 @@ import '../../../core/services/auth_token_store.dart';
|
||||
import '../../../core/services/oidc_redirect_guard.dart';
|
||||
import '../../../core/notifiers/auth_notifier.dart';
|
||||
import '../domain/login_challenge_resolver.dart';
|
||||
import '../domain/password_login_flow_policy.dart';
|
||||
import '../../profile/domain/notifiers/profile_notifier.dart';
|
||||
import '../../../core/services/web_window.dart';
|
||||
|
||||
@@ -742,7 +741,6 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
final localSessionMessage = tr(
|
||||
'msg.userfront.login.verification.approved_local',
|
||||
);
|
||||
final linkLoginMessage = tr('msg.userfront.login.link.approved');
|
||||
try {
|
||||
final res = await AuthProxyService.verifyLoginCode(
|
||||
sanitizedLoginId,
|
||||
@@ -872,7 +870,6 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
}
|
||||
|
||||
Future<void> _handlePasswordLogin() async {
|
||||
print("[Auth] _handlePasswordLogin START");
|
||||
final input = _passwordLoginIdController.text.trim();
|
||||
final password = _passwordController.text.trim();
|
||||
if (input.isEmpty || password.isEmpty) {
|
||||
@@ -889,29 +886,23 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
}
|
||||
|
||||
try {
|
||||
print("[Auth] Calling AuthProxyService.loginWithPassword...");
|
||||
final res = await AuthProxyService.loginWithPassword(
|
||||
loginId,
|
||||
password,
|
||||
loginChallenge: _loginChallenge,
|
||||
);
|
||||
print("[Auth] loginWithPassword response: $res");
|
||||
|
||||
final jwt = res['sessionJwt'] ?? res['sessionToken'] ?? res['token'];
|
||||
final provider = res['provider'] as String?;
|
||||
final redirectTo = res['redirectTo'] as String?;
|
||||
|
||||
if (jwt != null) {
|
||||
print("[Auth] JWT found, calling _onLoginSuccess. RedirectTo: $redirectTo");
|
||||
_onLoginSuccess(jwt, provider: provider, redirectTo: redirectTo);
|
||||
} else if (redirectTo != null && redirectTo.isNotEmpty) {
|
||||
print("[Auth] Only redirectTo found. Redirecting...");
|
||||
webWindow.redirectTo(redirectTo);
|
||||
} else {
|
||||
print("[Auth] No JWT and no redirectTo found.");
|
||||
}
|
||||
} catch (e) {
|
||||
print("[Auth] _handlePasswordLogin Error: $e");
|
||||
if (e.toString().contains("User not registered")) {
|
||||
_showUnregisteredDialog();
|
||||
} else {
|
||||
@@ -1134,56 +1125,44 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
}
|
||||
|
||||
Future<void> _onLoginSuccess(String token, {String? provider, String? redirectTo}) async {
|
||||
print("[Auth] _onLoginSuccess ENTRY. RedirectTo: $redirectTo, Token len: ${token.length}");
|
||||
|
||||
try {
|
||||
if (!mounted) {
|
||||
print("[Auth] _onLoginSuccess: Not mounted, returning.");
|
||||
return;
|
||||
}
|
||||
|
||||
// [Priority 1] Immediate External Redirection
|
||||
if (redirectTo != null && redirectTo.isNotEmpty) {
|
||||
print("[Auth] _onLoginSuccess: Has redirectTo. Saving token and redirecting...");
|
||||
try {
|
||||
final providerName = provider ?? AuthTokenStore.getProvider();
|
||||
print("[Auth] _onLoginSuccess: Provider resolved: $providerName");
|
||||
AuthTokenStore.setToken(token, provider: providerName);
|
||||
print("[Auth] _onLoginSuccess: Token saved to store.");
|
||||
} catch (stErr) {
|
||||
print("[Auth] _onLoginSuccess: FAILED to save token: $stErr");
|
||||
// ignore
|
||||
}
|
||||
|
||||
print("[Auth] Calling webWindow.redirectTo: $redirectTo");
|
||||
webWindow.redirectTo(redirectTo); // Removed await as it's void
|
||||
return;
|
||||
}
|
||||
|
||||
// [Priority 2] OIDC Challenge Handling
|
||||
if (_loginChallenge != null && _loginChallenge!.isNotEmpty) {
|
||||
print("[Auth] _onLoginSuccess: Has loginChallenge. Attempting auto-accept...");
|
||||
try {
|
||||
// Save token first, it's needed for acceptance
|
||||
final providerName = provider ?? AuthTokenStore.getProvider();
|
||||
AuthTokenStore.setToken(token, provider: providerName);
|
||||
print("[Auth] _onLoginSuccess: Token saved for auto-accept.");
|
||||
|
||||
final res = await AuthProxyService.acceptOidcLogin(
|
||||
_loginChallenge!,
|
||||
token: token,
|
||||
);
|
||||
final nextRedirectTo = res['redirectTo'] as String?;
|
||||
print("[Auth] Auto-accept response: $res");
|
||||
|
||||
if (nextRedirectTo != null && nextRedirectTo.isNotEmpty) {
|
||||
print("[Auth] OIDC login accepted. Redirecting to: $nextRedirectTo");
|
||||
webWindow.redirectTo(nextRedirectTo); // Removed await
|
||||
return;
|
||||
} else {
|
||||
print("[Auth] Auto-accept successful but no redirectTo provided.");
|
||||
}
|
||||
} catch (e) {
|
||||
print("[Auth] Auto-accept failed: $e");
|
||||
_showError(
|
||||
tr(
|
||||
'msg.userfront.login.oidc_failed',
|
||||
@@ -1193,7 +1172,6 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
}
|
||||
}
|
||||
|
||||
print("[Auth] _onLoginSuccess: Standard Login Flow");
|
||||
_logTokenDetails(token);
|
||||
|
||||
final providerName = provider ?? AuthTokenStore.getProvider();
|
||||
@@ -1205,7 +1183,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
try {
|
||||
await ref.read(profileProvider.notifier).loadProfile();
|
||||
} catch (e) {
|
||||
print("[Auth] Failed to pre-fetch profile: $e");
|
||||
// ignore
|
||||
}
|
||||
|
||||
final uri = Uri.base;
|
||||
@@ -1215,21 +1193,17 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
redirectParam != null && redirectParam.isNotEmpty;
|
||||
|
||||
if (WebAuthIntegration.isPopup() || hasRedirectParam) {
|
||||
print(
|
||||
"[Auth] External integration detected (popup or redirect). Notifying...",
|
||||
);
|
||||
WebAuthIntegration.sendLoginSuccess(token);
|
||||
AuthNotifier.instance.notify();
|
||||
return;
|
||||
}
|
||||
|
||||
print("[Auth] Login success. Navigating to root.");
|
||||
AuthNotifier.instance.notify();
|
||||
if (mounted) {
|
||||
context.go('/');
|
||||
}
|
||||
} catch (globalErr) {
|
||||
print("[Auth] CRITICAL ERROR in _onLoginSuccess: $globalErr");
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1286,10 +1286,12 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool canGoNext = false;
|
||||
if (_currentStep == 1 && _termsAccepted && _privacyAccepted)
|
||||
if (_currentStep == 1 && _termsAccepted && _privacyAccepted) {
|
||||
canGoNext = true;
|
||||
if (_currentStep == 2 && _isEmailVerified && _isPhoneVerified)
|
||||
}
|
||||
if (_currentStep == 2 && _isEmailVerified && _isPhoneVerified) {
|
||||
canGoNext = true;
|
||||
}
|
||||
if (_currentStep == 3) {
|
||||
final nameOk = _nameController.text.trim().isNotEmpty;
|
||||
if (_affiliationType == 'GENERAL') {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// ignore_for_file: avoid_print
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
@@ -120,7 +121,6 @@ final _router = GoRouter(
|
||||
GoRoute(
|
||||
path: '', // Matches /:locale
|
||||
builder: (context, state) {
|
||||
print("[Router] Building Dashboard (Root)");
|
||||
return const DashboardScreen();
|
||||
},
|
||||
),
|
||||
@@ -134,7 +134,6 @@ final _router = GoRouter(
|
||||
final loginChallenge = state.uri.queryParameters['login_challenge'];
|
||||
final redirectUrl = state.uri.queryParameters['redirect_uri'] ??
|
||||
state.uri.queryParameters['redirect_url'];
|
||||
print("[Router] Building /signin. Challenge: $loginChallenge");
|
||||
return LoginScreen(
|
||||
key: state.pageKey,
|
||||
loginChallenge: loginChallenge,
|
||||
@@ -149,7 +148,6 @@ final _router = GoRouter(
|
||||
final loginChallenge = state.uri.queryParameters['login_challenge'];
|
||||
final redirectUrl = state.uri.queryParameters['redirect_uri'] ??
|
||||
state.uri.queryParameters['redirect_url'];
|
||||
print("[Router] Building /login (as signin). Challenge: $loginChallenge");
|
||||
return LoginScreen(
|
||||
key: state.pageKey,
|
||||
loginChallenge: loginChallenge,
|
||||
@@ -162,12 +160,10 @@ final _router = GoRouter(
|
||||
builder: (BuildContext context, GoRouterState state) {
|
||||
final consentChallenge = state.uri.queryParameters['consent_challenge'];
|
||||
if (consentChallenge == null) {
|
||||
print("[Router] WARNING: Consent screen without challenge.");
|
||||
return const Scaffold(
|
||||
body: Center(child: Text('Error: Consent challenge is missing.')),
|
||||
);
|
||||
}
|
||||
print("[Router] Building /consent. Challenge: $consentChallenge");
|
||||
return ConsentScreen(consentChallenge: consentChallenge);
|
||||
},
|
||||
),
|
||||
@@ -200,7 +196,6 @@ final _router = GoRouter(
|
||||
GoRoute(
|
||||
path: 'l/:shortCode',
|
||||
builder: (context, state) {
|
||||
final shortCode = state.pathParameters['shortCode'];
|
||||
return LoginScreen(key: state.pageKey);
|
||||
},
|
||||
),
|
||||
@@ -264,11 +259,8 @@ final _router = GoRouter(
|
||||
final requestedLocale = extractLocaleFromPath(uri);
|
||||
final preferredLocale = resolvePreferredLocaleCode();
|
||||
|
||||
print("[Router] Redirect check for: $uri");
|
||||
|
||||
if (requestedLocale == null) {
|
||||
final localizedPath = buildLocalizedPath(preferredLocale, uri);
|
||||
print("[Router] Locale missing. Redirecting to: $localizedPath");
|
||||
return localizedPath;
|
||||
}
|
||||
|
||||
@@ -296,22 +288,12 @@ final _router = GoRouter(
|
||||
path.startsWith('/consent/') ||
|
||||
uri.path.contains('/consent');
|
||||
|
||||
print("[Router] Path: $path, IsLoggedIn: $isLoggedIn, IsPublic: $isPublicPath");
|
||||
|
||||
if (isPublicPath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isLoggedIn) {
|
||||
print("[Router] ACCESS DENIED. Redirecting to /signin");
|
||||
final locale = requestedLocale;
|
||||
final newPath = '/$locale/signin';
|
||||
|
||||
// Preserve ALL query parameters
|
||||
final finalRedirect = uri.replace(path: newPath);
|
||||
String result = finalRedirect.path;
|
||||
if (finalRedirect.hasQuery) result += '?${finalRedirect.query}';
|
||||
return result;
|
||||
return buildSigninRedirectPath(requestedLocale, uri);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
// ignore_for_file: avoid_web_libraries_in_flutter
|
||||
|
||||
import 'dart:html' as html;
|
||||
import 'package:web/web.dart' as web;
|
||||
|
||||
class WebStorage {
|
||||
bool get isWeb => true;
|
||||
|
||||
String? get(String key) => html.window.localStorage[key];
|
||||
String? get(String key) => web.window.localStorage.getItem(key);
|
||||
|
||||
void set(String key, String value) {
|
||||
html.window.localStorage[key] = value;
|
||||
web.window.localStorage.setItem(key, value);
|
||||
}
|
||||
|
||||
String? getSession(String key) => html.window.sessionStorage[key];
|
||||
String? getSession(String key) => web.window.sessionStorage.getItem(key);
|
||||
|
||||
void setSession(String key, String value) {
|
||||
html.window.sessionStorage[key] = value;
|
||||
web.window.sessionStorage.setItem(key, value);
|
||||
}
|
||||
|
||||
void removeSession(String key) {
|
||||
html.window.sessionStorage.remove(key);
|
||||
web.window.sessionStorage.removeItem(key);
|
||||
}
|
||||
|
||||
void clearSession() {
|
||||
html.window.sessionStorage.clear();
|
||||
web.window.sessionStorage.clear();
|
||||
}
|
||||
|
||||
void remove(String key) {
|
||||
html.window.localStorage.remove(key);
|
||||
web.window.localStorage.removeItem(key);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
html.window.localStorage.clear();
|
||||
web.window.localStorage.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user