search

Home  >  Q&A  >  body text

How can I maintain my next-auth user session and get data using the provided ID in other routes?

<p>What I want to achieve here is that whenever a user logs in, I want to store the data returned because the data contains an ID that I will use in other routes to get the data. When the user successfully logs in, he will be redirected to the /home route and the ID obtained from the session will be used to fetch the data. Everything works fine but if I refresh the home page the user becomes empty. </p> <p>This is what my [...nextauth].js file looks like.</p> <pre class="brush:php;toolbar:false;">import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import axios from "axios"; export default NextAuth({ providers: [ CredentialsProvider({ name: "credentials", credentials: { username: { label: "Username", type: "text", placeholder: "justin" }, password: {label: "Password",type: "password",placeholder: "******"}, }, async authorize(credentials, req) { const url = req.body.callbackUrl.split("/auth")[0]; const { username, password } = credentials; const user = await axios({ url: `${url}/api/user/login`, method: "POST", data: { username: username, password: password, }, "content-type": "application/json", }) .then((res) => { return res.data; }) .catch((err) => { if (err.response.data) { throw new Error(err.response.data); } else { return null; } return null; }); return user; }, }), ], callbacks: { jwt: ({ token, user }) => { if (user) { token.user = user; } return token; }, session: ({ session, token }) => { if (token) { session.user = token.user; } return session; }, }, pages: { signIn: "/auth/login", newUser: "/auth/register", }, });</pre> <p>这是我的/home路由的样子</p> <pre class="brush:php;toolbar:false;">import Card from "@/components/card/Card"; import React, { useEffect, useState } from "react"; import styles from "./home.module.css"; import { Ubuntu } from "@next/font/google"; import { useSession } from "next-auth/react"; import { useDispatch, useSelector } from "react-redux"; const ubuntu = Ubuntu({ weight: "500", subsets: ["cyrillic"] }); const getData = async (id) => { const res = await fetch({ url: "http://localhost:3000/api/note/getall", method: "POST", "content-type": "application/json", data: { id: id, }, }); if (!res.ok) { console.log(id); throw new Error("Unable to fetch"); } else { return res.json(); console.log(res); } }; function home() { const colors = ["#E9F5FC", "#FFF5E1", "#FFE9F3", "#F3F5F7"]; const random = Math.floor(Math.random() * 5); const rc = colors[random]; const [pop, setPop] = useState("none"); const { user } = useSelector((state) => state.user); const getDataa = async () => { console.log(user) const data = await getData(user._id); console.log(data); }; useEffect(() => { if (user) { alert(user) } }, []); return ( <div className={styles.home}> <header> <h3 className={ubuntu.className}> Hello, <br /> {user?.username}! </h3> <input type="text" placeholder="search" /> </header> <div className={styles.nav}> <h1 className={ubuntu.className}>Notes</h1> </div> <div className={styles.section}> <div className={styles.inner}> {/* {data && data.map((e) => ( <Card rawData={e} color={colors[Math.floor(Math.random() * colors.length)]} /> ))} */} </div> </div> <div className="new"></div> </div> ); } export default home;</pre></p>
P粉744691205P粉744691205462 days ago514

reply all(2)I'll reply

  • P粉428986744

    P粉4289867442023-08-26 13:25:30

    This code seems to create a problem/race condition because you are mixing two different ways of handling asynchronous Promise:

    const user = await axios({
      url: `${url}/api/user/login`,
      method: "POST",
      data: {
        username: username,
        password: password,
      },
      "content-type": "application/json",
    })
      .then((res) => {
        return res.data;
      })
      .catch((err) => {
        if (err.response.data) {
          throw new Error(err.response.data);
        } else {
          return null;
        }
        return null;
      });
    return user;

    should be changed to this:

    try {
      const user = await axios({
        url: `${url}/api/user/login`,
        method: "POST",
        data: {
          username: username,
          password: password,
        },
        "content-type": "application/json",
      });
      return user.data;
    } catch (err) {
      if (err.response.data) {
        throw new Error(err.response.data);
      } else {
        return null;
      }
    }

    Or like this:

    axios({
      url: `${url}/api/user/login`,
      method: "POST",
      data: {
        username: username,
        password: password,
      },
      "content-type": "application/json",
    }).then((res) => {
      return res.data;
    }).catch((err) => {
      if (err.response.data) {
        throw new Error(err.response.data);
      } else {
        return null;
      }
      return null;
    });

    reply
    0
  • P粉707235568

    P粉7072355682023-08-26 10:01:08

    Add this component to your App.js file:

    function Auth({ children }) {
      const router = useRouter();
      const { status } = useSession({
        required: true,
        onUnauthenticated() {
          router.push("/sign-in");
        },
      });
    
      if (status === "loading") {
        return 
    Loading ...
    ; } return children; }

    Now in your App function, instead of returning <Component {...pageProps} />, first check the component Does it have the auth attribute, so you wrap it in <Auth> to ensure that every component that requires a session will only be mounted after the session has finished loading (that's Why user is null because the session is still loading)

    {
      Component.auth ? (
        
          
        
      ) : (
        
      );
    }
    
    

    Finally, you add .auth = {} to each page where you want to define a session (Home in your case)

    const Home = () => {
    //....
    }
    Home.auth = {};
    

    This also helps redirect the user to the /sign-in page

    when the session expires

    reply
    0
  • Cancelreply