如何在React应用中集成Cognito托管UI并解决重刷新问题
解决Amplify托管UI联邦登录页面刷新与Context状态不同步问题
我遇到过完全一样的问题!托管UI的重刷新确实破坏了React单页应用的体验,而且会导致之前的Promise链中断,Context状态无法同步。这里有两个核心解决方案,既能解决状态不同步的问题,也能实现弹窗式登录避免页面刷新:
1. 先修复页面刷新后的状态同步问题(必做)
不管你用弹窗还是重定向,页面刷新后React Context的状态都会丢失,所以必须在应用初始化时主动检查用户的登录状态。修改你的provideAuthentication组件:
const provideAuthentication = Component => { class WithAuthentication extends React.Component { constructor(props) { super(props); this.state = { authUser: null, }; } componentDidMount() { // 关键:页面加载时主动获取当前登录用户 Auth.currentAuthenticatedUser({ bypassCache: false }) .then(user => this.setState({ authUser: user })) .catch(() => this.setState({ authUser: null })); // 保留原来的监听逻辑 this.props.amplifyClient.authUserChangeHandler((user) => { this.setState({authUser: user}); }); // 可选:用Hub监听认证事件,更及时同步状态 Hub.listen('auth', (data) => { const { payload } = data; if (payload.event === 'signIn') { Auth.currentAuthenticatedUser().then(user => this.setState({ authUser: user })); } else if (payload.event === 'signOut') { this.setState({ authUser: null }); } }); } render() { return ( <AuthUserContext.Provider value={this.state.authUser}> <Component {...this.props} /> </AuthUserContext.Provider> ); } } return withAmplify(WithAuthentication); };
这样页面刷新后,组件挂载时会主动调用Auth.currentAuthenticatedUser()获取用户,Context会立即更新,不会再出现“已登录却显示未登录”的情况。
2. 实现弹窗式托管UI(避免页面刷新)
如果你想彻底避免页面刷新,可以用弹窗打开托管UI,而不是重定向。修改你的AmplifyClient里的doSignIn方法:
doSignIn() { // 获取Amplify配置的托管UI登录地址 const { oauth } = Amplify.configure(); const authUrl = `${oauth.domain}/login?client_id=${oauth.clientId}&response_type=${oauth.responseType}&redirect_uri=${encodeURIComponent(oauth.redirectSignIn)}`; // 打开固定尺寸的认证弹窗 const authPopup = window.open(authUrl, 'AmplifyAuth', 'width=550,height=600,left=100,top=100'); // 轮询检查弹窗状态,关闭后同步用户信息 const checkPopup = setInterval(() => { if (authPopup.closed) { clearInterval(checkPopup); // 弹窗关闭后主动检查用户登录状态 Auth.currentAuthenticatedUser() .then(user => this.authUserChangeListeners.forEach(listener => listener(user))) .catch(() => this.authUserChangeListeners.forEach(listener => listener(null))); } }, 100); }
注意事项:
- 确保你的Amplify OAuth配置里,
redirectSignIn和redirectSignOut设置为当前应用的域名(比如http://localhost:3000),并且在AWS Cognito控制台里把这个域名添加到允许的回调URL和允许的注销URL列表中。 - 这种弹窗方式不需要修改Amplify的核心配置,只要回调URL配置正确即可正常工作。
为什么原来的方案会失败?
原来的Auth.federatedSignIn()会触发页面重定向,导致原来的React应用实例被销毁,Promise永远无法resolve,所以你的authUserChangeListeners永远不会被调用。而页面刷新后,新的应用实例没有主动获取用户状态,所以Context里的authUser还是null,就会显示“You must log in”。
通过上面的两个步骤,既能解决状态同步问题,也能实现无刷新的弹窗登录,完美适配React单页应用的开发理念。
内容的提问来源于stack exchange,提问作者Shifty
相关产品推荐
相关产品推荐

