我正在使用Amplify身份验证来处理身份验证.然而,在我做了Auth.signIn()Auth.confirmSignIn()(为了让用户输入6位代码)之后,

从钩子useAuthenticator返回的authStatus的值是'unauthenticated',而route的返回值仍然是'signIn'...

我只是在Auth.confirmSignIn()之后的Promise Resolve中拨打了window.location.reload()来"修复"这个问题,但它就是感觉不对……应该有更好的方式来通知Amplify我们已经成功登录.

问题是: 如何刷新身份验证状态以使useAuthenticator在我成功(自定义)登录时拾取?

代码(如果需要)-如下

登录组件的主要部分:

import { Amplify, Auth } from "aws-amplify";
import { CognitoUser } from "amazon-cognito-identity-js";
// other imports, component definition and local state...

const onSubmit = () => {
    Auth.signIn({
      username: state.username,
      password: state.password,
    })
      .then((response: CognitoUser) => {
        // if needed, do something custom with the response...
        // if we have a `customChallenge`
        if (resp.challengeName) {
          // navigate to ConfirmSignIn component which renders the form to enter authentication code (from SMS or the Authenticator app)
        }
      }
};
// component render() with username and password inputs and submit button...

ConfirSignIn组件的主要部分:

import { useAuthenticator } from "@aws-amplify/ui-react";
import { CognitoUser } from "amazon-cognito-identity-js";
// other imports, component definition and local state...

const onSubmit = useCallback(
    async (e: React.FormEvent) => {
      e.preventDefault();
      setLoading(true);
      await Auth.confirmSignIn(user, code, AmplifyChallengeName.SMS)
        .then(async csi_data => {
          // calling this doesn't work... doesn't refresh the `useAuthenticator` return values
          const cognitoUser: CognitoUser = await Auth.currentAuthenticatedUser({ bypassCache: true });
          const currentSession = await Auth.currentSession();

          // calling this doesn't work either...
          cognitoUser.refreshSession(currentSession.getRefreshToken(), (err, session) => {
            const { idToken, refreshToken, accessToken } = session;
          });

          // calling this works... but feels wrong
          // window.location.reload();
        });
      }

// component render() with code input and submit button...

下面是包含<Authenticator>的Login组件:

import { Authenticator, AuthenticatorProps, useAuthenticator } from "@aws-amplify/ui-react";
import AuthenticatorWrapper from "./AuthenticatorWrapper";
// other imports

const customizedAuthRoutes = ["signIn", "confirmResetPassword"]; //

// component definition...

  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>
  );

验证器包装:

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}</>;
}

推荐答案

In your SignIn component, you are using the Auth.signIn() method from AWS Amplify to manually sign in the user.
Then, in your ConfirmSignIn component, you are using the Auth.confirmSignIn() method to manually confirm the sign in.
So you're using the Auth methods to manually handle the sign in process.

但是,在您的验证器包装中,您将使用来自AWS Amplify UI的useAuthenticator钩子来获取身份验证状态.

换句话说,您同时使用了useAuthenticator hook and和AWS Amplify Auth方法.

useAuthenticator挂钩旨在与Authenticator组件一起使用来管理状态和UI,而AWS Amplify Auth方法(如signInconfirmSignIn)通常单独用于手动处理身份验证.

In your situation, you are mixing these two approaches. You are manually handling the sign-in process using the Auth methods, but you are relying on the useAuthenticator hook to update your application's state.
The problem is that the useAuthenticator hook is not aware of the changes to the user's authentication status when you manually sign in the user, which is why the authStatus remains 'unauthenticated'.


更好的方法是完全依赖Authenticator组件和useAuthenticator挂钩,或者手动处理身份验证过程并自己管理应用程序状态.第一种方法更简单,需要的代码更少,而第二种方法提供了更多的灵活性和可控性.

以下是如何修改登录过程以使用Authenticator组件和useAuthenticator挂钩的示例:

登录组件:

import { SignIn } from "@aws-amplify/ui-react";

const MySignIn = () => {
  return <SignIn />;
};

export default MySignIn;

Confirm登录组件:

import { ConfirmSignIn } from "@aws-amplify/ui-react";

const MyConfirmSignIn = () => {
  return <ConfirmSignIn />;
};

export default MyConfirmSignIn;

登录组件:

import { Authenticator } from "@aws-amplify/ui-react";
import { useState } from "react";
import MySignIn from "./MySignIn";
import MyConfirmSignIn from "./MyConfirmSignIn";

const MyLogin = () => {
  const [authState, setAuthState] = useState();
  const [user, setUser] = useState();

  return (
    <Authenticator
      onAuthStateChange={(nextAuthState, authData) => {
        setAuthState(nextAuthState);
        setUser(authData);
      }}
    >
      {authState === "signIn" && <MySignIn />}
      {authState === "confirmSignIn" && <MyConfirmSignIn />}
    </Authenticator>
  );
};

export default MyLogin;

在这里,Authenticator组件自动处理登录过程,onAuthStateChange属性用于在用户的身份验证状态更改时更新应用程序的状态.

Meaning: This code will render the MySignIn component when the authState is 'signIn', and the MyConfirmSignIn component when the authState is 'confirmSignIn'.
The onAuthStateChange prop of the Authenticator component will automatically update the authState and user when the authentication status changes.

这样,您将不需要手动使用Auth.signIn()Auth.confirmSignIn()个方法.Authenticator组件将为您处理所有身份验证流.

如果您希望继续手动处理身份验证过程,则需要自己管理应用程序状态.这可能涉及创建上下文或Redux存储来管理用户的身份验证状态,并在用户登录或注销时更新此状态.

Reactjs相关问答推荐

我想将状态设置为true,直到每一张卡片都生成并在多姆中呈现

URL参数和React路由中的点

cypress 不能点击SPAN

获取点击的国家/地区名称react 映射

有没有一种方法可以在没有强烈动画的情况下有条件地渲染组件?

如何使ionic 面包屑在州政府条件下可点击?

如何在物料界面react 的多选菜单中设置最大 Select 数限制

在任何渲染之前在ReactJs中获取数据

滚动视图样式高度没有任何区别

Symfony ux-react:使用react_component()时React组件不会渲染

如何使用服务器中的数据自动填充表单字段?

如何管理组件列表的复杂状态? (Nextjs/ReactJS)

如何解决使用react-hook-form和yup动态创建的输入不集中的问题

为 Next.js 应用程序目录中的所有页面添加逻辑的全局文件是什么?

React Router v6 路径中的符号

如何到达类组件中的状态?

作为单个变量的 React 组件是否比 memoized 组件渲染得更快?

React + i18next + Trans + Prettier:Prettier 最终会在重新格式化 JSX 时 destruct 翻译

React CSSTransition 两次创建新页面并在这两个相同的页面上运行转换

在 React 中,为什么不能向空片段添加键(短语法)?