سلام
وقتتون بخیر
بنده پروژه ای رو react، nodejs, MongoDB و express نوشتم
با استفاده از پکیج passport.js اعتبار سنجی فرم ورود به سایت رو انجام میدم بدین ترتیب پس از اینکه یوزر درخواست لاگین رو داد اطلاعاتش توسط این پکیج بررسی میشه و در صورت صحیح بودن، تائید رو برمیگیردونه و مقدار req.user هم اطلاعات یوزر اعم از یوزر و پسورد و سایر مشخصات فردی اون یوزر خواهد بود
اما الان تمام این مراحل موفقیت امیزه به جز مقدار req.user که undefined رو برمیگردونه مرحله به مرحله کد ها رو هم بررسی کردم متوجه شدم که تو روند اجرای کدها اصلا متد deserializeUser صدا زده نمیشه!
ممنون میشم راهنماییم کنید خیلی دنبال حل این مشکل تو استک اورفلو گشتم جوابی پیدا نکردم
کامپوننت لاگین از بخش فرانت اند
import axios from "axios";
import React, { Fragment, useState } from "react";
import { Link } from "react-router-dom";
import apiUrl from "../../../utils/apiPath.json";
const LoginForm = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [loadingState, setLoadingState] = useState(false);
const apiPath = apiUrl[0].serverAPI;
const loginHandler = () => {
setLoadingState(true);
axios
.post(
`${apiPath}/login`,
{ email, password },
{
headers: { "Access-Control-Allow-Origin": "http://localhost:3000" },
withCredentials: true,
}
)
.then((result) => {
setLoadingState(false);
console.log("result:", result.data);
})
.catch((e) => {
setLoadingState(true);
console.log(e);
});
};
return (
<Fragment>
<label for="email">نام کاربری</label>
<div className="input-group">
<input
type="email"
className="form-control text-center"
name="email"
id="email"
disabled={loadingState}
onChange={(e) => setEmail(e.target.value)}
/>
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-user"></i>
</div>
</div>
</div>
<label className="mt-4" for="password">
پسورد
</label>
<div className="input-group">
<input
type="password"
className="form-control text-center"
name="password"
id="password"
disabled={loadingState}
onChange={(e) => setPassword(e.target.value)}
/>
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-key"></i>{" "}
</div>
</div>
</div>
<br />
<div className="text-center">
<button
className="btn btn-info mx-2"
disabled={loadingState}
onClick={loginHandler}
>
ورود به سامانه
</button>
<Link
disabled={loadingState}
to="/forgetpassword"
className="btn btn-secondary"
>
فراموشی رمز عبور
</Link>
<br />
<br />
<p> در صورتی که در سامانه ثبت نام نکرده اید اینجا کلیک کنید.</p>
</div>
</Fragment>
);
};
export default LoginForm;
ساخت استراتژی پسپورت
const passport = require("passport");
const { Strategy } = require("passport-local");
const bcrypt = require("bcrypt");
const User = require("../models/user_auth");
//----- create new strategy
passport.use(
new Strategy({ usernameField: "email" }, async (email, password, done) => {
try {
const user = await User.findOne({ email });
// console.log(user);
if (!user) {
return done(null, false, {
message: "کاربری با این ایمیل ثبت نشده است",
});
}
const isMatch = await bcrypt.compare(password, user.password);
console.log(isMatch);
if (isMatch) {
// console.log(user);
return done(null, user); //user is avaliable at --> req.user
} else {
return done(null, false, {
message: "نام کاربری یا کلمه عبور صحیح نمی باشد.",
});
}
} catch (err) {
console.log(err);
}
})
);
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((_id, done) => {
console.log('deserializerUser is : ',_id);
User.findById(_id, (err, user) => {
done(err, user);
});
});
کد های مربوط به کنترل لاگین
const logHandler = (req, res,next) => {
passport.authenticate("local",{
successRedirect:'http://localhost:4000/loginsuccess',
failureRedirect:'http://localhost:4000/loginfailure',
failureFlash: true
})(req,res,next)
};
اسکریپت server.js
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const session = require("express-session");
const flash = require("express-flash");
const cors = require("cors");
const passport = require("passport");
const cookieParser = require("cookie-parser");
const DBConfig = require("./utils/DBConfig");
const user = require("./controller/users");
//*--------------------------------- end of packeges ------------------------------
mongoose
.connect(DBConfig.path, { useNewUrlParser: true })
.then(() => console.log("[MongoDB connected]"))
.catch((e) => console.log("[i cant connect to your MongoDB]"));
//*--------------------------------- end of Database ------------------------------
require("./config/passport");
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(
session({
secret: "secret",
cookie: { maxAge: 60000 },
resave: false,
saveUninitialized: false,
})
);
//* passport configuration
app.use(passport.initialize()); //must define this code after config session because passport use the cookie and session
app.use(passport.session());
app.use(flash());
app.use(
cors({
origin: "http://localhost:3000",
credentials: true
})
);
//*--------------------------------- end of MiddleWears ------------------------------
app.post("/register", user.regHandler);
app.post("/login", user.logHandler);
app.get("/loginsuccess", (req, res) => {
console.log("req.user:", req.user);
res.send(req.user);
});
app.get("/loginfailure", (req, res) => {
res.send("login Failed");
});
//*---------------------------------- end of Routes -----------------------------------
app.listen("4000", () => console.log("[server is running on port 4000]"));
سرور با پورت 4000 و فرانت با پورت 3000 پیکربندی شده اند
سلام نود جی اس کار نکردم، ولی یک سرچ کردم متوجه شدم این دوتا متد deserializeUser, serializeUser یجورایی میدلور درخواست های شما میشه اگر اشتباه نکنم!
توی استک فعلی که کار میکنم underline() برای پراویت کردن متغییر استفاده میشه، وقتی متد serializeUser صدا میزنید اطلاعاتی برمیگردونه؟ حالا اگر توی متد deserializeUser متغییر id رو بدون آندرلاین بنویسید نتیجه ی نمیده؟!
passport.deserializeUser((_id, done) => {
console.log('deserializerUser is : ',_id);
User.findById(_id, (err, user) => {
done(err, user);
});
});
جناب موسوی عزیز ممنونم از وقتی که گذاشتید
وقتی متد serializeUser رو صدا میزنم، متغیر user حاوی اطلاعات یوزر میشه که از داخل دیتابیس میگیره.
حقیقاً تو نت خیلی جستجو کردم، به نظر میاد که id رو باید بدون آندرلاین قرار بدم اما چون نتیجه نگرفتم، اومدم با آندرلاین گذاشتم چون تو مانگودیبی به صورت دیفالت، آی دی رو id ست میکنه. در هر صورت با هر دو حالتش نتیجه نگرفتم
console.log ای که تو متد desrializeUser نوشتم نشون میده این متد اصلاً صدا زده نمیشه چون چیزی برام لاگ نمیکنه
توی مستندات خود پکیج desrializeUser چطور صدا زده میشه؟! بعد از چه ریکویستی؟!
http://www.passportjs.org/docs/configure/
تفاوتی نکرد، از es6 به اینور تقریباً همه پکیج ها از ارو فانکشن پشتیبانی میکنند (البته به جزء یه میدلور ولیدیتور بود که پشتیبانی نمیکرد 😄)
به طور کلی سریالایز و دیسریالاز باید تو بخش استراتژی (یعنی تعیین نوع احراز هویت که در اینجا لوکال یا همون احراز هویت با یوزر و پسورد) نوشتن بشن که بعد از اینکه در بخش کنترولر لاگین (کداشو بالا گذاشتم) مشخصات یوزر رو از فرم ورود دریافت میکنه قسمت استراتژی صدا زده میشه که این قسمت هم شامل سه قسمت تعریف استراتژی، سریالایز و دیسریالایز میشه
سرچ کردم چندتا دلیل پیدا کردم یکیشون...
app.use(
session({
secret: "secret",
cookie: { maxAge: 60000 },
resave: false,
saveUninitialized: false,
})
,
cookie: {
secure: true
}
);
https://stackoverflow.com/questions/11277779/passportjs-deserializeuser-never-called
این پیامش رو برات ترجمه کردم
If you have cookie.secure set to true and you're NOT using SSL (i.e. https protocol) then the cookie with the session id is not returned to the browser and everything fails silently. Removing this flag resolved the problem for me - it took hours to realise this!
اگر cookie.secure را روی true تنظیم کردهاید و از SSL (یعنی پروتکل https) استفاده نمیکنید، کوکی با شناسه جلسه به مرورگر بازگردانده نمیشود و همه چیز بیصدا از کار میافتد. حذف این پرچم مشکل را برای من حل کرد - ساعت ها طول کشید تا متوجه این موضوع شدم!
یکجا دیگه هم خوندم اگر از روتر استفاده میکنید آدرس app.use خودت رو این شکلی بنویس
app.use('/book',passport.initialize(), isAuthorized, booksRouter)
https://github.com/jaredhanson/passport/issues/446#issuecomment-443406327
جناب موسوی بزرگوار، ابتدا که خیلی ممنونم که دارین این همه وقت میزارید
در خصوص زحمتی که دارید میکشید، چون دارم از لوکال استفاده میکنم، کوکی سکیور رو فالس قرار دادم
در مورد روتر ها، هم بعد از لاگین استفاده میشن و میتونیم با این سینتکسی که فرستادید تشخیص بدیم که آیا یوزر همچنان لاگین هستش و آیا به این صفحه دسترسی دارد؟ (البته که الان با این چیزی که برام فرستادید این روش برام جا افتاد و واقعاً ممنونم)
قربانت ❤ ، تلاش کردم اول بفهمم مسئله رو و بعد مشکلتون رو سرچ کنم ولی فکر کنم دوستان دیگه ی که nodejs, reactjs و mongoDb کار کرده باشند بهتر میتونن راهنمایی کنند 😅👌
آیا مایل به ارسال نوتیفیکیشن و اخبار از طرف راکت هستید ؟