Пользовательская страница входа NextAuth не работает с параллельными вкладками

Я пытаюсь использовать функцию учетных данных nextauth на своем веб-сайте. Теперь проблема в следующем: когда я создаю пользовательскую страницу входа и отправляю данные с помощью функции входа, она работает нормально. Но проблема в том, что когда я открываю новое окно, после чего я вхожу в систему из одного окна, изменение должно отражаться и в другом окне. Но это отражается только в одном окне, и когда я обновляю окно, оно отражается в другом.

ПРИМЕЧАНИЕ. Когда я использую страницу входа по умолчанию, которая поставляется с /api/auth/signin, она работает отлично. Кроме того, когда я использую redirect:true в функции signIn, она также работает нормально, но не с redirect:false.

Вот код страницы signin.js:

      import {
  Alert,
  Box,
  Button,
  Container,
  Divider,
  LinearProgress,
  TextField,
  Typography,
} from "@mui/material";

import { yupResolver } from "@hookform/resolvers/yup";
import Grid from "@mui/material/Unstable_Grid2";
import { getCsrfToken, signIn, useSession } from "next-auth/react";
import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { useDispatch } from "react-redux";
import * as yup from "yup";
import { getUserProfile } from "../../redux/actions/userActions";
import {
  loginFail,
  loginPending,
  loginSuccess,
} from "../../redux/slices/loginSlice";
import NoteAlert from "../../components/global/noteAlert";

function SignIn(props) {
  const schema = yup.object().shape({
    email: yup
      .string()
      .email("Must be a valid email")
      .max(100)
      .required("Required: This field is required."),
    password: yup
      .string()
      .required("No password provided.")
      .min(8, "Password is too short - should be 8 chars minimum."),
  });

  const { data: session, status } = useSession();
  const loading = status === "loading";

  const [alertMeta, setAlertMeta] = useState(null);
  const dispatch = useDispatch();
  const router = useRouter();

  useEffect(() => {
    session
      ? session.isAdmin
        ? router.push("/dashboard/admin")
        : session && session.user.isCompany
        ? router.push("/dashboard/company")
        : router.push("/dashboard/user")
      : null;
  }, [session]);
  const {
    formState: { errors },
    register,
    control,
    setValue,
    handleSubmit,
    getValues,
  } = useForm({
    defaultValues: {},
    resolver: yupResolver(schema),
    mode: "onChange", // or 'onBlur' for example
  });

  const onSubmit = async (values) => {
    setAlertMeta({ severity: "info", message: "verifying details" });
    dispatch(loginPending());
    const data = await signIn("credentials", {
      redirect: false,
      email: values.email,
      password: values.password,
    });
    if (data.status === 200 && data.error === null) {
      setAlertMeta({
        severity: "success",
        message: "successfully logged in",
      });
      dispatch(loginSuccess());

      dispatch(getUserProfile(values.email));
      // router.push(data.url);
    } else {
      setAlertMeta({
        severity: "error",
        message: "It seems email or the password is incorrect",
      });

      return dispatch(loginFail("Error While Signing In. Code: 3kxE94kks"));
    }
  };
  return (
    <>
      {!loading && !session && (
        <Container maxWidth="md">
          <Box
            style={{
              boxShadow: "rgba(100, 100, 111, 0.2) 0px 7px 29px 0px",
              borderRadius: "15px",
            }}
            sx={{ my: 10, p: 5 }}
          >
            <Typography
              variant="h4"
              align="center"
              component="h1"
              sx={{ mb: 3 }}
              className="xunderline"
            >
              <strong>sign in to your account</strong>
            </Typography>
            <br />
            <form onSubmit={handleSubmit(onSubmit)}>
              <input
                name="csrfToken"
                type="hidden"
                defaultValue={props.csrfToken}
              />

              <Grid container spacing={3}>
                <Grid xs={12} sm={12} md={12} lg={12}>
                  <Controller
                    name="email"
                    control={control}
                    defaultValue=""
                    render={({ field }) => (
                      <TextField
                        variant="outlined"
                        required
                        type="email"
                        fullWidth
                        {...field}
                        autoComplete="current-password"
                        label="email"
                      />
                    )}
                  />
                  {errors.email && (
                    <Alert severity="error" sx={{ my: 1 }}>
                      {errors.email.message}
                    </Alert>
                  )}
                </Grid>

                <Grid xs={12} sm={12} md={12} lg={12}>
                  <Controller
                    name="password"
                    control={control}
                    defaultValue=""
                    render={({ field }) => (
                      <TextField
                        variant="outlined"
                        fullWidth
                        required
                        type="password"
                        {...field}
                        label="password"
                      />
                    )}
                  />
                  {errors.password && (
                    <Alert severity="error" sx={{ my: 1 }}>
                      {errors.password.message}
                    </Alert>
                  )}
                </Grid>
              </Grid>
              <br />
              {alertMeta !== null && (
                <>
                  <LinearProgress color="info" />
                  <Box textAlign="center" sx={{ mt: 2 }}>
                    <Alert severity={alertMeta.severity}>
                      {alertMeta.message}
                    </Alert>{" "}
                    <br />
                  </Box>
                </>
              )}
              <Box textAlign="center">
                <Button align="center" type="submit" variant="contained">
                  sign in
                </Button>
                <Divider light sx={{ my: 2 }} />
              </Box>
              <Grid container>
                <Grid xs={12} md={6}>
                  <NoteAlert
                    link="/auth/signup"
                    linkText="forgot password? reset here"
                  />
                </Grid>
                <Grid xs={12} md={6}>
                  <NoteAlert
                    link="/auth/signup"
                    linkText="don't have an account? create one"
                  />
                </Grid>
              </Grid>
            </form>
          </Box>
        </Container>
      )}
    </>
  );
}

export default SignIn;

export async function getStaticProps(context) {
  // const csrfToken = await getCsrfToken(context);
  return {
    props: {
      csrfToken: await getCsrfToken(context),
    },
  };
}

[...nextauth].js

      import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import userSchema from "../../../models/user/userSchema";
import { comparePassword } from "../../../helpers/hashHelper";
import initDB from "../../../helpers/initDB";

initDB();
export default NextAuth({
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        email: { label: "Email", type: "text", placeholder: "your@email.com" },
        password: {
          label: "Password",
          type: "password",
          placeholder: "********",
        },
      },
      async authorize(credentials, req) {
        const lowerMail = credentials.email.toString().toLowerCase();
        const user = await userSchema.findOne({ email: lowerMail });

        if (user._id) {
          const passFromDb = user && user._id ? user.password : null;
          const result = await comparePassword(
            credentials.password,
            passFromDb
          );

          if (result) {
            return user;
          } else {
            return null;
          }
        }
      },
    }),
  ],

  secret: process.env.NEXTAUTH_SECRET,

  session: {
   
    strategy: "jwt",

  
  },

 
  jwt: {
   
  },

  
  pages: {
    signIn: "/auth/signin", // Displays signin buttons
  
  },

  
  // when an action is performed.
  // https://next-auth.js.org/configuration/callbacks
  callbacks: {
    
    async redirect({ url, baseUrl }) {
      return baseUrl;
    },
    async session({ session, token, user }) {
    
      session.user.isCompany = token.isCompany;
      session.user._id = token._id;
      session.isAuthor = token.isAuthor;
      session.isAdmin = token.isAdmin;

      return session;
    },
    async jwt({ token, user, account, profile, isNewUser }) {
      if (user) {
        token.isCompany = user.isCompany;
        token._id = user._id;
        token.isAuthor = user.isAuthor;
        token.isAdmin = user.isAdmin;
      }
      return token;
    },
  },

  events: {},

  theme: {
    colorScheme: "light",
  },

  // Enable debug messages in the console if you are having problems
  debug: true,
});

компонент header.js

      import Link from "next/link";
import { signIn, signOut, useSession } from "next-auth/react";
import styles from "./header.module.css";

// The approach used in this component shows how to build a sign in and sign out
// component that works on pages which support both client and server side
// rendering, and avoids any flash incorrect content on initial page load.
export default function Header() {
  const { data: session, status } = useSession();
  const loading = status === "loading";

  return (
    <header>
      <noscript>
        <style>{`.nojs-show { opacity: 1; top: 0; }`}</style>
      </noscript>
      <div className={styles.signedInStatus}>
        <p
          className={`nojs-show ${
            !session && loading ? styles.loading : styles.loaded
          }`}
        >
          {!session && (
            <>
              <span className={styles.notSignedInText}>
                You are not signed in
              </span>
              <a
                href={`/api/auth/signin`}
                className={styles.buttonPrimary}
                onClick={(e) => {
                  e.preventDefault();
                  signIn();
                }}
              >
                Sign in
              </a>
            </>
          )}
          {session?.user && (
            <>
              {session.user.image && (
                <span
                  style={{ backgroundImage: `url('${session.user.image}')` }}
                  className={styles.avatar}
                />
              )}
              <span className={styles.signedInText}>
                <small>Signed in as</small>
                <br />
                <strong>{session.user.email ?? session.user.name}</strong>
              </span>
              <a
                href={`/api/auth/signout`}
                className={styles.button}
                onClick={(e) => {
                  e.preventDefault();
                  signOut();
                }}
              >
                Sign out
              </a>
            </>
          )}
        </p>
      </div>
      here comes the menu item
    </header>
  );
}

1 ответ

Обновлять:

я добавилawait useSession()после отправки данных, и теперь он работает нормально, как и ожидалось.

Другие вопросы по тегам