Amplify登录成功后authState仍为unauthenticated,如何刷新useAuthenticator状态?
问题描述
我正在使用Amplify Auth处理认证流程,但执行Auth.signIn()和Auth.confirmSignIn()(让用户输入6位验证码)后,useAuthenticator钩子返回的authStatus仍为'unauthenticated',route也停留在'signIn'状态。目前我通过在Auth.confirmSignIn()的Promise回调中调用window.location.reload()临时解决,但这种方式并不合理,应该有更好的方法通知Amplify登录已成功。请问如何刷新认证状态,让useAuthenticator识别到已完成的自定义登录?
相关代码
SignIn组件核心代码
import { Amplify, Auth } from "aws-amplify"; import { CognitoUser } from "amazon-cognito-identity-js"; // 其他导入、组件定义和本地状态... const onSubmit = () => { Auth.signIn({ username: state.username, password: state.password, }) .then((response: CognitoUser) => { // 如有需要,对响应进行自定义处理... // 如果存在`customChallenge` if (resp.challengeName) { // 跳转到ConfirmSignIn组件,该组件渲染输入验证码(来自短信或认证器应用)的表单 } } }; // 组件render()包含用户名、密码输入框和提交按钮...
ConfirmSignIn组件核心代码
import { useAuthenticator } from "@aws-amplify/ui-react"; import { CognitoUser } from "amazon-cognito-identity-js"; // 其他导入、组件定义和本地状态... const onSubmit = useCallback( async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); await Auth.confirmSignIn(user, code, AmplifyChallengeName.SMS) .then(async csi_data => { // 调用这个没用...无法刷新`useAuthenticator`的返回值 const cognitoUser: CognitoUser = await Auth.currentAuthenticatedUser({ bypassCache: true }); const currentSession = await Auth.currentSession(); // 调用这个也没用... cognitoUser.refreshSession(currentSession.getRefreshToken(), (err, session) => { const { idToken, refreshToken, accessToken } = session; }); // 调用这个有用...但感觉不太对 // window.location.reload(); }); } // 组件render()包含验证码输入框和提交按钮...
包含<Authenticator>的Login组件
import { Authenticator, AuthenticatorProps, useAuthenticator } from "@aws-amplify/ui-react"; import AuthenticatorWrapper from "./AuthenticatorWrapper"; // 其他导入 const customizedAuthRoutes = ["signIn", "confirmResetPassword"]; // // 组件定义... const renderCustomizedRoute = useCallback(() => { switch (route) { case "signIn": return <SignIn />; case "confirmResetPassword": default: return ( <ConfirmResetPassword /> ); } }, [route]); return ( <AuthenticatorWrapper> {customizedAuthRoutes.includes(route) ? ( renderCustomizedRoute() ) : ( <Authenticator services={services} className="Login" hideSignUp components={components} formFields={formFields} > {children} </Authenticator> )} </AuthenticatorWrapper> );
AuthenticatorWrapper组件
export default function AuthenticatorWrapper({ children }: PropsWithChildren) { const { authStatus } = useAuthenticator(context => [context.authStatus]); if (authStatus === "unauthenticated") { return ( <div className="LogoContentCopyrightLayout"> <Logo className="LoginLogo" /> {children} <Copyright /> </div> ); } return <> {children} </>; }
解决方案
问题根源在于自定义登录组件没有接入Amplify UI的状态管理体系,导致useAuthenticator无法感知认证状态变化。以下是几种标准解决方案:
1. 直接使用useAuthenticator封装的认证方法
Amplify UI的useAuthenticator钩子已经内置了与状态同步绑定的signIn和confirmSignIn方法,调用这些方法会自动更新authStatus和route:
修改ConfirmSignIn组件
import { useAuthenticator } from "@aws-amplify/ui-react"; const ConfirmSignIn = () => { const { confirmSignIn } = useAuthenticator(); // ...本地状态定义 const onSubmit = useCallback(async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); try { await confirmSignIn({ confirmationCode: code, challengeName: AmplifyChallengeName.SMS }); // 成功后useAuthenticator会自动切换authStatus为authenticated,route跳转至已登录页面 } catch (err) { // 处理认证失败逻辑 } finally { setLoading(false); } }, [code, confirmSignIn]); // ...组件渲染逻辑 };
修改SignIn组件
import { useAuthenticator } from "@aws-amplify/ui-react"; const SignIn = () => { const { signIn } = useAuthenticator(); // ...本地状态定义 const onSubmit = async () => { try { await signIn({ username: state.username, password: state.password }); // 若存在认证挑战,useAuthenticator会自动切换到对应的route(如confirmSignIn) } catch (err) { // 处理登录失败逻辑 } }; // ...组件渲染逻辑 };
2. 手动触发状态同步(适合特殊自定义场景)
如果必须直接使用Auth类的原生方法,可通过Amplify的Hub事件系统手动通知状态变化:
import { useAuthenticator, Hub } from "@aws-amplify/ui-react"; import { Auth } from "aws-amplify"; const ConfirmSignIn = () => { // ...本地状态定义 useEffect(() => { // 监听Auth事件,自动同步状态 const listener = Hub.listen('auth', (data) => { if (data.payload.event === 'signIn') { // 触发useAuthenticator状态刷新 window.dispatchEvent(new Event('storage')); } }); return () => listener(); }, []); const onSubmit = useCallback(async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); try { await Auth.confirmSignIn(user, code, AmplifyChallengeName.SMS); // 手动派发登录成功事件 Hub.dispatch('auth', { event: 'signIn' }); } catch (err) { // 处理错误 } finally { setLoading(false); } }, [user, code]); // ...组件渲染逻辑 };
3. 修正Authenticator上下文范围
当前Login组件中,自定义路由组件未包裹在<Authenticator>内部,导致上下文状态无法共享。应将自定义组件通过components属性注入Authenticator:
import { Authenticator } from "@aws-amplify/ui-react"; import SignIn from "./SignIn"; import ConfirmResetPassword from "./ConfirmResetPassword"; const Login = ({ children }) => { return ( <AuthenticatorWrapper> <Authenticator services={services} className="Login" hideSignUp components={{ signIn: SignIn, confirmResetPassword: ConfirmResetPassword }} formFields={formFields} > {children} </Authenticator> </AuthenticatorWrapper> ); };
此方式下,自定义组件会自动接入Authenticator的状态上下文,无需额外处理状态同步。
内容的提问来源于stack exchange,提问作者Filip Savic
相关产品推荐
相关产品推荐

