Authentication 如何在电子邮件/密码验证后自动登录用户

Authentication 如何在电子邮件/密码验证后自动登录用户,authentication,next.js,mongodb-realm,Authentication,Next.js,Mongodb Realm,我目前正在使用NextJS、ApolloClient和MongoDB+MongoRealm构建一个博客示例应用程序。NextJS框架是在框架的官方页面教程之后构建的。 目前,新用户可以通过访问发送到“pages/signup”的注册表单进行注册。输入凭据后,他们将被重定向到主页。然后,新登录的用户必须访问另一个页面,即与“pages/login”root相关联的页面,该页面包含登录表单,该表单负责对其电子邮件/密码进行身份验证。 此外,我还设置了Realm,以便在用户的电子邮件地址发送确认电子邮

我目前正在使用NextJS、ApolloClient和MongoDB+MongoRealm构建一个博客示例应用程序。NextJS框架是在框架的官方页面教程之后构建的。 目前,新用户可以通过访问发送到“pages/signup”的注册表单进行注册。输入凭据后,他们将被重定向到主页。然后,新登录的用户必须访问另一个页面,即与“pages/login”root相关联的页面,该页面包含登录表单,该表单负责对其电子邮件/密码进行身份验证。 此外,我还设置了Realm,以便在用户的电子邮件地址发送确认电子邮件。该电子邮件包含一个指向my 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;
下面是我的confirm.js文件,它负责从确认URL中提取令牌和令牌ID。此组件通常仅在客户端收到电子邮件并单击确认链接时呈现,该链接基本上具有表单/confirm,其中每个令牌都是一个字符串,并按领域添加到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;
currentUser基本上代表Realm.app.currentUser,并由我的提供商提供给_应用程序

所以,问题是我的确认组件没有访问电子邮件和密码字段的权限。 我曾尝试使用useContext钩子在同级组件之间传递数据,但很快就放弃了这种方法,因为我不想在整个NextJS页面中传递敏感数据。我应该使用密码的唯一地方是MongoDB POST请求期间,因为它由Realm Web加密

我有办法解决这个问题吗?也许是完全不同的方法


提前非常感谢!任何帮助都将不胜感激

如果禁用用户电子邮件确认,则可能会在注册完成后调用登录功能,如下所示:

registerAndLoginemail,密码 .然后=> 登录电子邮件、密码 .then=>router.push'/' .catcherr=>抛出错误 .catcherr=>抛出错误 我用你的帖子解决了我的一个错误,所以顺便谢谢你。
希望我的答案有效,我没有时间测试。

在后端进行身份验证。您需要对照数据库中存储的散列密码检查普通用户密码。您可以在本地存储由auth MethodsHanks生成的令牌以供评论!:事实上,这通常发生在服务器上。但是,ApolloClient和MongoDB Realm使用捆绑到NextJs应用程序中的一些依赖项和node.js包,为您提供了直接从客户端进行身份验证的机会。Apollo客户端基本上使用GraphQL和Mongo领域接口进行查询,Mongo领域接口反过来与Atlas进行通信。我不会将密码存储到Atlas中。目前,我将它们存储在Realm中,但在过渡到JWT身份验证后,情况会有所改变。我已经成功地在我的应用程序中创建并验证了用户,唯一的问题是我希望用户在创建帐户后立即登录。这不是一个重要的问题,但是,如果我找不到任何新的方法,也许我会让它保持这种状态。你可以找到更多关于ApolloClient的信息,并在这里作出反应:整个Mongo相关的文档非常稀少,但是,通关有点痛苦,Benjamin!谢谢你的回答!很高兴你发现我的帖子很有用最后,我不得不使用Google Firebase身份验证,因此用户创建过程现在由该服务处理。不过,我会在完成更紧急的事情后尝试你的想法。我认为它更简单,通常只是在确认后将用户重定向到登录页面。所以只需一个router.push/login就足够了。您是否可以提供完整的身份验证useAuth&&useRealm代码,因为关于领域身份验证的文档太少了。。。不过你似乎挺成功的。也许我还必须切换到Firebase,因为它有更多的文档!当然没问题!这是我的Git:我得到了一些帮助 我的一些有经验的朋友但关键是将整个应用程序包装在一个“领域提供程序”、“Apollo客户端提供程序”和一个“缓存提供程序”中。这是因为你必须在整个应用程序中访问当前用户相关信息。此外,如果没有领域实例,您将无法与Mongo对话。但是,为了确保一切都清楚,最好是克隆我的repo,运行“npm install”,并尝试按照代码进行操作。您可以查看相应的分支,了解您需要的信息。请随时问我任何问题:。
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;