Пользовательская страница входа 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()
после отправки данных, и теперь он работает нормально, как и ожидалось.