Flutter接入AWS Cognito修改页面逻辑后登录报错idToken为null
问题背景
调整应用逻辑从启动强制登录改为先浏览内容再触发登录后,点击登录按钮触发Cognito异常,控制台报错如下:
W/CognitoUserSession(22147): CognitoUserSession is not valid because idToken is null. D/AWSMobileClient(22147): Sending password. D/AWSMobileClient(22147): Using USER_SRP_AUTH for flow type. E/UserContextDataProvider(22147): Exception in creating JSON from context data E/amplify:flutter:auth_cognito(22147): AuthException I/flutter (22147): Could not login - Sign in failed
触发原因
- AuthService设计存在状态不一致问题:
authStateController被定义为静态属性,但loginWithCredentials、showLogin等核心方法是实例方法,调整后监听的是静态stream,但传入页面的是实例方法,两者操作的状态不互通,导致本地残留无效的空token会话。 - 缺少初始化状态校验:应用启动时没有先等待Amplify初始化完成就加载页面,也没有主动调用
checkAuthStatus清理本地残留的无效会话,本地之前缓存的空idToken会话干扰了新的登录请求。 - TabBarFlow状态不更新:在
initState中一次性初始化了_widgetOptions,传入SettingsPage的authFlowStatus是初始化时的固定值,后续auth状态变化时不会同步更新,导致页面状态和实际鉴权状态不匹配。
修复方案
- 统一AuthService的状态管理
把AuthService改成单例模式,避免静态和实例方法混用导致的状态不一致,修改示例:
class AuthService { // 单例实现 static final AuthService _instance = AuthService._internal(); factory AuthService() => _instance; AuthService._internal(); // 去掉static修饰,统一用单例实例访问 final authStateController = StreamController<AuthState>.broadcast(); late AuthCredentials _credentials; void showNone() { final state = AuthState(authFlowStatus: AuthFlowStatus.none); authStateController.add(state); } // 其余方法同理去掉static修饰,logOut方法也改为非静态 void logOut() async { try { await Amplify.Auth.signOut(); final state = AuthState(authFlowStatus: AuthFlowStatus.none); authStateController.add(state); } on AuthException catch (authError) { print('Could not log out - ${authError.message}'); } } // ...其余方法保持原有逻辑不变 }
调整main.dart中stream的监听为单例实例的stream:
stream: AuthService().authStateController.stream,
所有调用AuthService方法的地方都统一用AuthService().方法名调用。
- 新增初始化校验逻辑
在应用启动时先完成Amplify初始化,再调用checkAuthStatus初始化鉴权状态,示例:
// 在main函数或者应用根组件的initState中执行 Future<void> _initAmplify() async { try { await Amplify.addPlugin(AmplifyAuthCognito()); await Amplify.configure(amplifyconfig); // 初始化完成后再校验鉴权状态 AuthService().checkAuthStatus(); } catch(e) { print('Amplify初始化失败: $e'); } }
- 修复TabBarFlow的状态更新逻辑
不要在initState中固定_widgetOptions,改到build方法中构建,保证authFlowStatus变化时同步更新:
@override Widget build(BuildContext context) { // 放到build里每次状态变化都重新生成widget列表 final _widgetOptions = <Widget>[ HomePage(), SearchAvatarPage(), SelectAvatarPage(), MyPage(), SettingsPage( authFlowStatus: widget.authFlowStatus, shouldShowSignUp: widget.shouldShowSignUp, shouldShowLogin: widget.shouldShowLogin ) ]; return Scaffold( // 原有布局逻辑保持不变 ); }
- 登录前清理本地无效会话
在loginWithCredentials方法开头新增本地会话清理逻辑,避免残留空token干扰:
void loginWithCredentials(AuthCredentials credentials) async { try { // 先清理本地残留的无效会话,未登录时signOut报错直接忽略 try { await Amplify.Auth.signOut(options: SignOutOptions(globalSignOut: false)); } catch(_) {} // 原有登录逻辑保持不变 final result = await Amplify.Auth.signIn( username: credentials.username, password: credentials.password ); // ...后续逻辑保持不变 } on AuthException catch (authError) { print('Could not login - ${authError.message}'); } }
- 兼容Cognito高级安全特性报错
如果仍然出现UserContextDataProvider相关错误,可升级amplify_auth_cognito到最新稳定版,或者到AWS Cognito控制台的用户池-高级安全设置中,关闭"启用高级安全"特性即可解决。
内容的提问来源于stack exchange,提问作者gs97ahn
相关产品推荐
相关产品推荐

