You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 08:18:13