我试图在Fastify中创建一个简单、肮脏的身份验证流。
值通过带有Postgres数据库的Prisma进行回签,通过bcrypt进行回签然后转换为JWT
这是代码:
const login: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
fastify.post("/", async function (request: any, reply) {
console.log("Request");
if (request.body.username && request.body.password) {
await prisma.user
.findFirst({
where: { name: request.body.username },
})
.then(async (user) => {
console.log("prisma");
if (!user?.id) {
console.log("User not found");
return reply.code(404).send({ message: "User not found" });
} else {
if (bcrypt.compareSync(request.body.password, user!.hash)) {
console.log("Password correct");
await jwt.sign(
{ user: user },
process.env.SECRET || "",
{ expiresIn: "365d" },
(err: any, token: any) => {
if (err) {
console.log("Error");
return reply.code(500).send({ message: "Error" });
} else {
console.log("JWT");
return reply.code(200).send({ jwt: token });
}
}
);
} else {
console.log("Password incorrect");
return reply.code(500).send({ message: "Password incorrect" });
}
}
});
} else {
console.log("Missing username or password");
return reply.code(400).send({ message: "Missing user or password" });
}
});
}
我尝试记录任何步骤,但没有抛出重复的日志。
这就是错误:
[App] Request
[App] prisma
[App] Password correct
[App] JWT
[23:29:19.419] INFO (23324): incoming request
[App] reqId: "req-1"
[App] req: {
[App] "method": "POST",
[App] "url": "/users/login",
[App] "hostname": "127.0.0.1:3000",
[App] "remoteAddress": "127.0.0.1",
[App] "remotePort": 1042
[App] }
[App] [23:29:19.576] WARN (23324): Reply already sent
[App] reqId: "req-1"
[App] err: {
[App] "type": "FastifyError",
[App] "message": "Reply was already sent.",
[App] "stack":
[App] FastifyError: Reply was already sent.
[App] at _Reply.Reply.send (C:UsersmichaWebstormProjectsLIBManbackendnode_modulesfastifylibreply.js:118:26)
[App] at C:UsersmichaWebstormProjectsLIBManbackenddistroutesusersloginindex.js:29:56
[App] at C:UsersmichaWebstormProjectsLIBManbackendnode_moduleslodash.onceindex.js:71:21
[App] at SignStream.<anonymous> (C:UsersmichaWebstormProjectsLIBManbackendnode_modulesjsonwebtokensign.js:201:9)
[App] at Object.onceWrapper (node:events:642:26)
[App] at SignStream.emit (node:events:527:28)
[App] at SignStream.sign (C:UsersmichaWebstormProjectsLIBManbackendnode_modulesjwslibsign-stream.js:64:10)
[App] at SignStream.<anonymous> (C:UsersmichaWebstormProjectsLIBManbackendnode_modulesjwslibsign-stream.js:46:12)
[App] at Object.onceWrapper (node:events:641:28)
如果我遗漏了一些明显的东西,我会提前道歉请求返回空
正如您已经发现的,问题是async/await+than
和回调的混合。
它导致代码难以阅读,并且有许多边缘情况,因为您不知道何时以及哪些代码将首先执行(回调或等待之后的语句(。
请注意,prisma
查询上有相同的模式,而不仅仅是JWT代码上。
让我向您展示完全异步/等待风格的代码:
async function login(fastify, opts) {
fastify.post("/", async function (request, reply) {
console.log("Request");
// first thing first: we are avoiding to naste the code in if/else statements
if (!request.body.username || !request.body.password) {
console.log("Missing username or password");
return reply.code(400).send({ message: "Missing user or password" });
}
const user = await prisma.user.findFirst({
where: { name: request.body.username },
})
console.log("prisma");
if (!user?.id) {
console.log("User not found");
return reply.code(404).send({ message: "User not found" });
}
if (!bcrypt.compareSync(request.body.password, user.hash)) {
console.log("Password incorrect");
return reply.code(500).send({ message: "Password incorrect" });
}
console.log("Password correct");
const token = await jwt.sign(
{ user: user },
process.env.SECRET || "",
{ expiresIn: "365d" },
)
console.log("JWT");
// using async handlers, you can return a json instead of calling reply.send
return { jwt: token }
});
}
我在尝试了很多之后发现了我的错误:
Fastify不喜欢JWT代币签名过程是异步的,它似乎返回了两次。
这很简单,只需将JWT进程更改为不使用回调,而只是作为let返回即可。
请访问此答案。它更好、更详细地解释了
嘿,你的代码看起来有点乱,所以我可以自由地清理一下所有的东西,希望这能奏效。请告诉我问题是否仍然存在
const login: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
fastify.post("/", async function (request: any, reply) {
console.log("Request");
if (!request.body.username || !request.body.password) {
return reply.code(400).send({ message: "Missing user or password" });
}
const user = await prisma.user.findFirst({ where: { name: request.body.username }})
console.log("prisma");
if(!user?.id) {
console.log("User not found");
return reply.code(404).send({ message: "User not found" });
}
if (!bcrypt.compareSync(request.body.password, user!.hash)) {
console.log("Password incorrect");
return reply.code(500).send({ message: "Password incorrect" });
}
console.log("Password correct");
await jwt.sign({ user: user }, process.env.SECRET || "", { expiresIn: "365d" }, (err: any, token: any) => {
if (err) {
console.log("Error");
return reply.code(500).send({ message: "Error" });
}
console.log("JWT");
return reply.code(200).send({ jwt: token });
}
});
}