必须提供 jwt 在 NextJs 13 中出现错误

问题描述 投票:0回答:1

我得到的错误是:data: { error: '必须提供jwt' }

当用户通过提供正确的电子邮件和密码登录时,用户将被重定向 到“/”页面,逻辑写在 middleware.ts 中,您可以在这段代码中看到。但是使用 React 查询显示错误,为什么正常的 axios.get 可以工作,但这个不起作用。 我的项目中需要 tanstack 查询,因此尝试在此 UserDetails.jsx 中使用它来显示 存储在login/route.ts中的用户信息

UserDetails.tsx (This code doesnot work):
    "use client";
    
    interface Data {
      id: string;
      username: string;
      email: string;
    }
    
    export default function UserDetails() {
      const { data } = useQuery({
        queryFn: async () => {
          const { data } = await axios.get("http://localhost:3000/api/me");
          return data as Data;
        },
      });
    
      return (
        <div>
          <h1>{JSON.stringify(data)}</h1>
        </div>
      );
    }

这是登录 api,它接受电子邮件和密码并进行验证,验证后生成 jwt 令牌并将其存储在 httponly cookie 中

 export async function POST(request: NextRequest) {
      try {
        const body = await request.json();
    
        const schema = z.object({
          email: z.string().email({ message: "Invalid Email !!" }),
          password: z.string(),
        });
    
        if (body.email === "" && body.password === "") {
          return NextResponse.json(
            { error: "Please fill all the fields !!" },
            { status: 400 }
          );
        }
    
        if (body.email === "") {
          return NextResponse.json(
            { error: "Email is required !!" },
            { status: 400 }
          );
        }
    
        if (body.password === "") {
          return NextResponse.json(
            { error: "Password is required !!" },
            { status: 400 }
          );
        }
    
        const validatedData = schema.parse(body);
        const { email, password } = validatedData;
    
        const user = await FindByEmail(email);
    
        if (!user) {
          return NextResponse.json(
            { error: "User doesn't Exists !!" },
            { status: 400 }
          );
        }
    
        const passwordsMatched = await user.matchPasswords(password);
        if (!passwordsMatched) {
          return NextResponse.json(
            { error: "Password is incorrect !!" },
            { status: 400 }
          );
        }
    
        const tokenData = {
          id: user._id,
          username: user.username,
          email: user.email,
        };
    
        const token = await jwt.sign(tokenData, process.env.JWT_SECRET!, {
          expiresIn: "1d",
        });
    
        const response = NextResponse.json(
          {
            message: "Login Successful",
          },
          { status: 200, statusText: "set cookie" }
        );
    
        response.cookies.set("jwt", token, {
          secure: true,
          httpOnly: process.env.NODE_ENV !== "development",
          sameSite: "strict",
          maxAge: 1 * 24 * 60 * 60 * 1000,
        });
    
        return response;
      } catch (error) {
        if (error instanceof z.ZodError) {
          return NextResponse.json({ error: error.flatten() }, { status: 400 });
        } else {
          return NextResponse.json(
            {
              error: "Something went wrong !!" + error,
            },
            { status: 400 }
          );
        }
      }
    }

该api用于获取用户信息

api/me/route.ts :

    
    connect();
    
    export async function GET(request: NextRequest) {
      try {
        const userId = await getDataFromToken(request);
        const user = await User.findOne({ _id: userId }).select("-password");
        return NextResponse.json({
          message: "User Found",
          data: user,
        });
      } catch (error: any) {
        return NextResponse.json({ error: error.message }, { status: 400 });
      }
    }

这用于从 jwt 令牌获取 id,因为 id 与用户名一起存储在 jwt 中 和电子邮件

getDataFromToken.ts : 
    import { NextRequest } from "next/server";
    import jwt from "jsonwebtoken";
    
    export const getDataFromToken = (request: NextRequest) => {
      try {
        const token = request.cookies.get("jwt")?.value || "";
        const decodedToken: any = jwt.verify(token, process.env.JWT_SECRET!);
        return decodedToken.id;
      } catch (error: any) {
        throw new Error(error.message);
      }
    };

这是 NextJs 提供的 middleware.ts,它检查 cookie 是否有 jwt 令牌或 不是,如果该令牌有效,则重定向到“/”页面,否则不是

middleware.ts:
    import { verifyJwtToken } from "@/libs/verifyToken";
    import { NextResponse } from "next/server";
    import { NextRequest } from "next/server";
    
    export async function middleware(request: NextRequest) {
      const token = request.cookies.get("jwt")?.value;
      const path = request.nextUrl.pathname;
      const PublicPath = path === "/login" || path === "/register";
    
      try {
        const verifiedToken =
          token &&
          (await verifyJwtToken(token).catch((e) => {
            throw new Error(e);
          }));
    
        if (PublicPath && token && verifiedToken) {
          return NextResponse.redirect(new URL("/", request.nextUrl));
        }
    
        if (!PublicPath && (!token || !verifiedToken)) {
          return NextResponse.redirect(new URL("/login", request.nextUrl));
        }
      } catch (error) {
        return NextResponse.redirect(new URL("/login", request.nextUrl));
      }
    }
    
    export const config = {
      matcher: ["/login", "/register", "/"],
    };

此代码用于验证 jwt 令牌是否有效,是否使用 jose,以及是否使用 jwt 有效然后发送与其关联的有效负载。

verifyToken.ts:
    import { jwtVerify } from "jose";
    
    export const getJwtSecretKey = () => {
      const secret = process.env.JWT_SECRET!;
      if (!secret || secret.length === 0) {
        throw new Error("The environment variable JWT_SECRET is not set.");
      }
      return secret;
    };
    
    export async function verifyJwtToken(token: string) {
      try {
        if (!token) {
          return;
        }
        const verified = await jwtVerify(
          token,
          new TextEncoder().encode(getJwtSecretKey())
        );
        return verified.payload;
      } catch (error: any) {
        throw new Error("Your token is expired");
      }
    }

但是这段代码可以工作:

"use client"; 
    import axios from "axios"; 
    import { useEffect, useState } from "react";
    export default function UserDetails() {
      const [userData, setUserData] = useState({
        name: "",
        email: "",
      });
    
      useEffect(() => {
        const getUserDetails = async () => {
          const res = await axios.get("/api/me");
          if (res.status === 200) {
            setUserData({
              name: res.data.data.username,
              email: res.data.data.email,
            });
          }
        };
        getUserDetails();
      }, []);
    
      return (
        <div>
          <h1>{userData.name}</h1>
          <h1>{userData.email}</h1>
        </div>
      );
    }
authentication jwt middleware next.js13
1个回答
0
投票

在登录API中,您将过期时间设置为1d

const token = await jwt.sign(tokenData, process.env.JWT_SECRET!, {expiresIn: "1d",});

这意味着,如果一天后您尝试验证它;给出错误

解决这个问题;

从您的开发或本地主机服务器中删除 cookie {转到个人资料并注销} 再次登录就不会出现任何错误

© www.soinside.com 2019 - 2024. All rights reserved.