NEXTJSを使用してTwitterをクローンする(ユーザーpassportを使用してログイン)
設定 npm i passport passport-local express-session
passportは名前のように、自分のサイトにアクセスする際にパスポートなどの役割を果たします.
passport-ローカルでログインを直接実施します.
express-sessionはpassportを使用してログインし、ユーザー情報をセッションに保存します.
passport設定
passport/local.js const passport = require("passport");
const { Strategy: LocalStrategy } = require("passport-local");
const bcrypt = require("bcrypt");
const { User } = require("../models");
module.exports = () => {
passport.use(
new LocalStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
const user = await User.findOne({
where: { email },
});
if (!user) {
return done(null, false, { reason: "존재하지 않는 이메일입니다!" });
}
const result = await bcrypt.compare(password, user.password);
if (result) {
return done(null, user);
}
return done(null, false, { reason: "비밀번호가 틀렸습니다." });
} catch (error) {
console.error(error);
return done(error);
}
}
)
);
};
usernameFieldと passwordFieldは、どのフォームフィールドからアイデンティティとパスワードを受信するかを設定するオプションです.上の場合はbodyのデータです { email: 'JaeHoon', password: '123' }
これにより,後のコールバック関数のemail値はJaeHoon,password値は123となる.
Eメールとパスワードの値が受信された場合は、コールバック関数が実行され、その内容を表示すると、Eメールでユーザーが見つかり、ユーザーが存在しない場合はエラーメッセージが送信されます.
userが存在する場合は、パスワードbcryptを使用します.と呼びます.パスワードが一致しない場合は、パスワードが間違っていることを示すエラーメッセージが送信されます.
パスワードが正しい場合はdone(null,user)を返します.はい.
doneパラメータは3つのパラメータを受け入れます.
1つ目:データベース・クエリーなどの場合にサーバにエラーを追加します.無条件に失敗した場合にのみ使用します.
2つ目:成功したときに返される値を入力します.
3つ目:パスワードエラーを表示したい場合に使用できます.これはサーバエラーではなく、ユーザーがランダムに作成したエラーなので、ユーザーに直接エラーメッセージを書きます.
passport/index.js
const passport = require("passport");
const local = require("./local");
const { User } = require("../models");
module.exports = () => {
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findOne({ where: { id } });
done(null, user); // req.user
} catch (error) {
console.error(error);
done(error);
}
});
local();
};
serializeUserはログインが成功したばかりの時に実行されます done(null, user);
からユーザオブジェクトを受信セッション(正確には、 req.session.passport.user
). セッションがある場合は、ページの移動時にログイン情報が変更されない可能性があります.非user.私があなたにidをあげたのはメモリを節約するためです.
逆シーケンス化ユーザセッション情報(SerializeUserに格納)と実際のデータベースのデータ
比較する.対応するユーザ情報がある場合、doneの第2のパラメータはreq.user
に保存され、要求処理時にユーザの情報はreq.user
を介して伝達される.
SerializeUserからdoneのユーザーに移動します.idは逆シーケンス化ユーザの最初のパラメータとして渡されるため、2つのタイプは常に一致しなければならない.
app.js
const express = require("express");
const cors = require("cors");
const session = require("express-session");
const cookieParser = require("cookie-parser");
const passport = require("passport");
const dotenv = require("dotenv");
const postRouter = require("./routes/post.js");
const userRouter = require("./routes/user.js");
const db = require("./models");
const passportConfig = require("./passport");
dotenv.config();
const app = express();
db.sequelize
.sync()
.then(() => {
console.log("DB 연결 성공");
})
.catch(err => {
console.error(err);
});
passportConfig();
app.use(
cors({
origin: true,
credentials: false,
})
); // argumnet로 {origin: true}로 해주면 *대신 보낸곳의 주소가 자동으로 들어간다.
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
session({
saveUninitialized: false,
resave: false,
secret: process.env.COOKIE_SECRET,
})
);
app.use(passport.initialize());
app.use(passport.session());
app.get("/", (req, res) => {
res.send("Hi");
});
app.use("/post", postRouter);
app.use("/user", userRouter);
app.listen(3065, () => {
console.log("서버 실행 중");
});
中間セッションの設定 session()
, passport.initialize()
, passport.session()
この部分を忘れずに入れてください前にはpassportConfig()もあります.入れますよ
router/user.js
const express = require("express");
const bcrypt = require("bcrypt");
const passport = require("passport");
const { User } = require("../models");
const router = express.Router();
...
router.post("/login", (req, res, next) => {
passport.authenticate("local", (err, user, info) => {
if (err) {
console.error(error);
return next(error);
}
if (info) {
//401은 허가되지않음
return res.status(401).send(info.reason);
}
return req.login(user, loginError => {
if (loginError) {
console.log(loginError);
return next(loginError);
}
return res.status(200).json(user);
});
})(req, res, next);
});
module.exports = router;
顧客がrouterのloginを介してpostリクエストを送信すると、passport.authenticate
が実行されます.この操作を実行すると、前に作成したポリシーが実行されます.(passport/local.js)ポリシーがdone()を返すと、passport.authenticate
のコールバック関数が実行されます.コールバック関数のパラメータにはdoneのような3つのパラメータが含まれ、3つのパラメータがコールバック関数のパラメータとしてdoneに送信される.
doneに最初のパラメータ値を入れるとreturn next(error);はい.
3番目のパラメータ値をdoneに入れるとres.status(401)が返されます.send(info.reason);はい.
userをdoneとして2番目のパラメータ値に渡すとreqが返されます.loginが実行されます.passport/indexも併用します.js上のpassport.SerializeUserが実行されます.このセッションのuser.idを保存します.
その後res.status(200)に戻ります.json(user)を介してクッキーとuserをフロントに送信する.
クッキーでサーバpassportから.逆シーケンス化されたユーザによって、対応するCookieのユーザに割り当てられる.idを見つけてuserを見つけてreq.ユーザー情報をuserに挿入します.
logout
const express = require("express");
const bcrypt = require("bcrypt");
const passport = require("passport");
const { User } = require("../models");
const router = express.Router();
...
router.post("logout", (req, res) => {
req.logout();
req.session.destroy();
res.send("ok");
})
module.exports = router;
Front
Postリクエストをバックエンドに送信し、ユーザーに関する情報を取得します.function logInAPI(data) {
return axios.post("/user/login", data);
}
function* logIn(action) {
try {
console.log("saga Login");
const result = yield call(logInAPI, action.data); //call fork 차이 fork는 비동기 call은 동기
yield put({
type: LOG_IN_SUCCESS,
data: result.data,
});
} catch (err) {
yield put({
//put은 dispatch라고 생각하면 된다.
type: LOG_IN_FAILURE,
error: err.response.data,
});
}
}
function* watchLogIn() {
yield takeLatest(LOG_IN_REQUEST, logIn);
}
export default function* userSaga() {
yield all([
fork(watchLogIn),
fork(watchLogOut),
fork(watchSignUp),
fork(watchFollow),
fork(watchUnfollow),
]);
}
インポートしたユーザー情報をstateに配置します.const reducer = (state = initialState, action) => {
return produce(state, draft => {
switch (action.type) {
// LOG IN
case LOG_IN_REQUEST:
draft.logInLoading = true;
draft.logInError = false;
draft.logInDone = null;
break;
case LOG_IN_SUCCESS:
draft.logInLoading = false;
draft.logInDone = true;
draft.me = action.data;
break;
case LOG_IN_FAILURE:
draft.logInLoading = false;
draft.logInError = action.error;
draft.logInDone = false;
break;
...
}
});
};
Reference
この問題について(NEXTJSを使用してTwitterをクローンする(ユーザーpassportを使用してログイン)), 我々は、より多くの情報をここで見つけました
https://velog.io/@abc5259/NEXTJS-로-twitter클론-해보기user-passport를-활용하여-login하기
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
npm i passport passport-local express-session
passport/local.js
const passport = require("passport");
const { Strategy: LocalStrategy } = require("passport-local");
const bcrypt = require("bcrypt");
const { User } = require("../models");
module.exports = () => {
passport.use(
new LocalStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
const user = await User.findOne({
where: { email },
});
if (!user) {
return done(null, false, { reason: "존재하지 않는 이메일입니다!" });
}
const result = await bcrypt.compare(password, user.password);
if (result) {
return done(null, user);
}
return done(null, false, { reason: "비밀번호가 틀렸습니다." });
} catch (error) {
console.error(error);
return done(error);
}
}
)
);
};
usernameFieldと passwordFieldは、どのフォームフィールドからアイデンティティとパスワードを受信するかを設定するオプションです.上の場合はbodyのデータです { email: 'JaeHoon', password: '123' }
これにより,後のコールバック関数のemail値はJaeHoon,password値は123となる.Eメールとパスワードの値が受信された場合は、コールバック関数が実行され、その内容を表示すると、Eメールでユーザーが見つかり、ユーザーが存在しない場合はエラーメッセージが送信されます.
userが存在する場合は、パスワードbcryptを使用します.と呼びます.パスワードが一致しない場合は、パスワードが間違っていることを示すエラーメッセージが送信されます.
パスワードが正しい場合はdone(null,user)を返します.はい.
doneパラメータは3つのパラメータを受け入れます.
1つ目:データベース・クエリーなどの場合にサーバにエラーを追加します.無条件に失敗した場合にのみ使用します.
2つ目:成功したときに返される値を入力します.
3つ目:パスワードエラーを表示したい場合に使用できます.これはサーバエラーではなく、ユーザーがランダムに作成したエラーなので、ユーザーに直接エラーメッセージを書きます.
passport/index.js
const passport = require("passport");
const local = require("./local");
const { User } = require("../models");
module.exports = () => {
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findOne({ where: { id } });
done(null, user); // req.user
} catch (error) {
console.error(error);
done(error);
}
});
local();
};
serializeUserはログインが成功したばかりの時に実行されます done(null, user);
からユーザオブジェクトを受信セッション(正確には、 req.session.passport.user
). セッションがある場合は、ページの移動時にログイン情報が変更されない可能性があります.非user.私があなたにidをあげたのはメモリを節約するためです.逆シーケンス化ユーザセッション情報(SerializeUserに格納)と実際のデータベースのデータ
比較する.対応するユーザ情報がある場合、doneの第2のパラメータは
req.user
に保存され、要求処理時にユーザの情報はreq.user
を介して伝達される.SerializeUserからdoneのユーザーに移動します.idは逆シーケンス化ユーザの最初のパラメータとして渡されるため、2つのタイプは常に一致しなければならない.
app.js
const express = require("express");
const cors = require("cors");
const session = require("express-session");
const cookieParser = require("cookie-parser");
const passport = require("passport");
const dotenv = require("dotenv");
const postRouter = require("./routes/post.js");
const userRouter = require("./routes/user.js");
const db = require("./models");
const passportConfig = require("./passport");
dotenv.config();
const app = express();
db.sequelize
.sync()
.then(() => {
console.log("DB 연결 성공");
})
.catch(err => {
console.error(err);
});
passportConfig();
app.use(
cors({
origin: true,
credentials: false,
})
); // argumnet로 {origin: true}로 해주면 *대신 보낸곳의 주소가 자동으로 들어간다.
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
session({
saveUninitialized: false,
resave: false,
secret: process.env.COOKIE_SECRET,
})
);
app.use(passport.initialize());
app.use(passport.session());
app.get("/", (req, res) => {
res.send("Hi");
});
app.use("/post", postRouter);
app.use("/user", userRouter);
app.listen(3065, () => {
console.log("서버 실행 중");
});
中間セッションの設定 session()
, passport.initialize()
, passport.session()
この部分を忘れずに入れてください前にはpassportConfig()もあります.入れますよrouter/user.js
const express = require("express");
const bcrypt = require("bcrypt");
const passport = require("passport");
const { User } = require("../models");
const router = express.Router();
...
router.post("/login", (req, res, next) => {
passport.authenticate("local", (err, user, info) => {
if (err) {
console.error(error);
return next(error);
}
if (info) {
//401은 허가되지않음
return res.status(401).send(info.reason);
}
return req.login(user, loginError => {
if (loginError) {
console.log(loginError);
return next(loginError);
}
return res.status(200).json(user);
});
})(req, res, next);
});
module.exports = router;
顧客がrouterのloginを介してpostリクエストを送信すると、passport.authenticate
が実行されます.この操作を実行すると、前に作成したポリシーが実行されます.(passport/local.js)ポリシーがdone()を返すと、passport.authenticate
のコールバック関数が実行されます.コールバック関数のパラメータにはdoneのような3つのパラメータが含まれ、3つのパラメータがコールバック関数のパラメータとしてdoneに送信される.doneに最初のパラメータ値を入れるとreturn next(error);はい.
3番目のパラメータ値をdoneに入れるとres.status(401)が返されます.send(info.reason);はい.
userをdoneとして2番目のパラメータ値に渡すとreqが返されます.loginが実行されます.passport/indexも併用します.js上のpassport.SerializeUserが実行されます.このセッションのuser.idを保存します.
その後res.status(200)に戻ります.json(user)を介してクッキーとuserをフロントに送信する.
クッキーでサーバpassportから.逆シーケンス化されたユーザによって、対応するCookieのユーザに割り当てられる.idを見つけてuserを見つけてreq.ユーザー情報をuserに挿入します.
logout
const express = require("express");
const bcrypt = require("bcrypt");
const passport = require("passport");
const { User } = require("../models");
const router = express.Router();
...
router.post("logout", (req, res) => {
req.logout();
req.session.destroy();
res.send("ok");
})
module.exports = router;
Front
Postリクエストをバックエンドに送信し、ユーザーに関する情報を取得します.
function logInAPI(data) {
return axios.post("/user/login", data);
}
function* logIn(action) {
try {
console.log("saga Login");
const result = yield call(logInAPI, action.data); //call fork 차이 fork는 비동기 call은 동기
yield put({
type: LOG_IN_SUCCESS,
data: result.data,
});
} catch (err) {
yield put({
//put은 dispatch라고 생각하면 된다.
type: LOG_IN_FAILURE,
error: err.response.data,
});
}
}
function* watchLogIn() {
yield takeLatest(LOG_IN_REQUEST, logIn);
}
export default function* userSaga() {
yield all([
fork(watchLogIn),
fork(watchLogOut),
fork(watchSignUp),
fork(watchFollow),
fork(watchUnfollow),
]);
}
インポートしたユーザー情報をstateに配置します.const reducer = (state = initialState, action) => {
return produce(state, draft => {
switch (action.type) {
// LOG IN
case LOG_IN_REQUEST:
draft.logInLoading = true;
draft.logInError = false;
draft.logInDone = null;
break;
case LOG_IN_SUCCESS:
draft.logInLoading = false;
draft.logInDone = true;
draft.me = action.data;
break;
case LOG_IN_FAILURE:
draft.logInLoading = false;
draft.logInError = action.error;
draft.logInDone = false;
break;
...
}
});
};
Reference
この問題について(NEXTJSを使用してTwitterをクローンする(ユーザーpassportを使用してログイン)), 我々は、より多くの情報をここで見つけました https://velog.io/@abc5259/NEXTJS-로-twitter클론-해보기user-passport를-활용하여-login하기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol