2

私は現在、NextJS、ApolloClient、および MongoDB + MongoRealm を使用して、ブログ サンプル アプリを作成しています。NextJS スケルトンは、フレームワークの公式ページのチュートリアルの後に構築されました。現時点では、新しいユーザーは「pages/signup」にあるサインアップ フォームにアクセスしてサインアップできます。資格情報を入力すると、ホームページにリダイレクトされます。次に、新たにサインインしたユーザーは、別のページ ('pages/login' ルートに関連付けられているページ) にアクセスする必要があります。このページには、電子メール/パスワード認証を担当するログイン フォームが含まれています。また、ユーザーのメール アドレスに確認メールを送信するように Realm を設定しました。電子メールには、確認を処理する NextJs アプリからのカスタマイズされたページへのリンクが含まれています (サインインを要求した後、ユーザーも確認する必要があります)。

これでワークフローが確立されます。ただし、ユーザーがログインした直後に自動的にログインしたい(アカウントを作成するときに、サインインしてログインページにアクセスする必要がないようにするため)。

私が直面している問題は、ユーザーの確認を処理する React コンポーネントが、ユーザー インスタンスの電子メールとパスワードにアクセスできないことです。ユーザーの資格情報にアクセスせずに、ユーザーをログインする方法が必要です。

以下では、そもそもなぜこのアクセス制限が発生するのかを正確に説明しようと思います。「_app.js」全体がいくつかのカスタム プロバイダーにラップされていますが、できるだけシンプルにしようとしているので、このトピックに必要なものだけを示します。

私のsignup.jsファイルは次のようになります。

import { useForm } from "react-hook-form";
// Used 'useForm' hook to simplify data extraction from the //input form
import { useAuth } from "members";

const SignUpForm = () => {
  const router = useRouter();
  const { handleSubmit, register } = useForm();
  const { signup } = useAuth();

  const signUpAndRedirect = (form) => {
  signup(form.email, form.password);
  router.push("/");
  // after signing up, redirect client back to home
  };

  return (
{/*My form's 'email' and 'password' fields are only accessible in the SignUpForm component*/}
    <div>
      <form onSubmit={handleSubmit(signUpAndRedirect)}>
        ...
       ...
      </form>
    </div>
  );
};

export default SignUpForm;

私の login.js ファイルは同じ概念に従って構築されています。唯一の違いは、「signUpAndRedirect」が「authenticateAndRedirect」に置き換えられていることです。

const authenticateAndRedirect = (form) => {
    login(form.email, form.password);
    router.push("/");
  };

そして、これが私の confirm.js ファイルで、確認 URL からトークンと tokenId を抽出します。このコンポーネントは通常、クライアントが電子メールを受信し、確認リンク (基本的には /confirm の形式で、各トークンは文字列であり、Realm によって URL に追加されます) をクリックしたときにのみレンダリングされます。

import Link from "next/link";
import { useEffect } from "react";
import { useRouter } from "next/router";
import { useAuth } from "members";

const Confirm = () => {
  const router = useRouter();
  const { confirm, login } = useAuth();
  useEffect(() => {
    const token = router.query.token;
    const tokenId = router.query.tokenId;

    if (token && tokenId) {
      confirm(token, tokenId);
      login(email, password); // !!! I don't have access to these
    }
  }, [router]);
//used useEffect() to assure the confirmation only happens once, after the component was rendered.

  return (
    <div>
      <h2>
        Thank you for confirming your email. Your profile was      successfully
        activated.
      </h2>
      <Link href="/">
        <a>Go back to home</a>
      </Link>
    </div>
  );
};

export default Confirm;

そして最後に、カスタマイズされたプロバイダーを通じてアクセスできるサインアップ、ログイン、確認の方法を簡単に見てみましょう。私はそれらが正しく動作することを確信しています:

const client = () => {
  const { app, credentials } = useRealm();
    const [currentUser, setCurrentUser] = useState(app.currentUser || false);
  const [isAuthenticated, setIsAuthenticated] = useState(user ? true : false);

  
  // Login and logout using email/password.

  const login = async (email, password) => {
    try {
      const userCredentials = await credentials(email, password);
      await app.logIn(userCredentials);

      setCurrentUser(app.currentUser);
      setIsAuthenticated(true);
    } catch (e) {
      throw e;
    }
  };

  const logout = async () => {
    try {
      setUser(null);

      // Sign out from Realm and Auth0.
      await app.currentUser?.logOut();
      // Update the user object.
      setCurrentUser(app.currentUser);
      setIsAuthenticated(false);
      setUser(false);
    } catch (e) {
      throw e;
    }
  };

  const signup = async (email, password) => {
    try {
      await app.emailPasswordAuth.registerUser(email, password);
      // await app.emailPasswordAuth.resendConfirmation(email);
    } catch (e) {
      throw e;
    }
  };

  const confirm = async (token, tokenId) => {
    try {
      await app.emailPasswordAuth.confirmUser(token, tokenId);
    } catch (e) {
      throw e;
    }
  };

  return {
    currentUser,
    login,
    logout,
    signup,
    confirm,
  };
};

export default client;

currentUser は基本的に Realm.app.currentUser を表し、プロバイダーによって _app に提供されます。

したがって、問題は、私の Confirm コンポーネントがメールとパスワードのフィールドにアクセスできないことです。兄弟コンポーネント間でデータを渡すために useContext フックを使用しようとしましたが、NextJS ページ全体で機密データを渡したくないため、このアプローチをすぐに放棄しました (パスワードを使用する必要がある唯一の場所は、 MongoDB POST リクエスト (Realm Web によって暗号化されるため)。

この問題を解決する方法はありますか? たぶん、まったく異なるアプローチですか?

事前にどうもありがとうございました!どんな助けでも大歓迎です!

4

1 に答える 1