我得到的错误是: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>
);
}
在登录API中,您将过期时间设置为1d
const token = await jwt.sign(tokenData, process.env.JWT_SECRET!, {expiresIn: "1d",});
这意味着,如果一天后您尝试验证它;给出错误
解决这个问题;
从您的开发或本地主机服务器中删除 cookie {转到个人资料并注销} 再次登录就不会出现任何错误