// solution.js
// Not code written by me. This is example code
import express from "express";
import bodyParser from "body-parser";
import pg from "pg";
import bcrypt from "bcrypt";
import passport from "passport";
import { Strategy } from "passport-local";
import session from "express-session";
import env from "dotenv";
const app = express();
const port = 3000;
const saltRounds = 10;
env.config();
app.use(
session({
secret: "TOPSECRETWORD",
resave: false,
saveUninitialized: true,
})
);
/*
1. **`secret` (비밀 키)**:
- `secret`은 세션 데이터를 암호화하는 데 사용되는 비밀 키입니다.
- 이 값은 무작위로 생성된 문자열로, 세션 데이터의 보안을 강화합니다.
- 다른 사람이 이 값을 알게 되면 세션 데이터가 노출될 수 있으므로, 보안 상 주의해야 합니다.
2. **`resave`**:
- `resave`는 세션 데이터가 변경되지 않았더라도 서버에 다시 저장할지 여부를 결정합니다.
- `false`로 설정하면 세션 데이터가 변경되지 않았을 때도 서버에 저장하지 않습니다.
- 일반적으로 `false`로 설정하여 성능을 최적화합니다.
3. **`saveUninitialized`**:
- `saveUninitialized`는 초기화되지 않은 세션 데이터를 저장할지 여부를 결정합니다.
- `true`로 설정하면 초기화되지 않은 세션 데이터도 저장됩니다.
- 사용자가 로그인하지 않은 경우에도 세션을 생성하고 저장하려면 `true`로 설정합니다.
*/
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("public"));
app.use(passport.initialize());
app.use(passport.session());
/*
1. **Passport 설정 및 사용**:
- `passport` 모듈을 가져옵니다.
- `app.use(passport.initialize())`와 `app.use(passport.session())`을 통해 Passport를 초기화하고 세션 관리를 설정합니다.
*/
const db = new pg.Client({
user: "postgres",
host: "localhost",
database: "secrets",
password: "123456",
port: 5432,
});
db.connect();
app.get("/", (req, res) => {
res.render("home.ejs");
});
app.get("/login", (req, res) => {
res.render("login.ejs");
});
app.get("/register", (req, res) => {
res.render("register.ejs");
});
app.get("/logout", (req, res) => {
req.logout(function (err) {
if (err) {
return next(err);
}
res.redirect("/");
});
});
app.get("/secrets", (req, res) => {
// console.log(req.user);
if (req.isAuthenticated()) {
res.render("secrets.ejs");
} else {
res.redirect("/login");
}
});
app.post(
"/login",
passport.authenticate("local", {
successRedirect: "/secrets",
failureRedirect: "/login",
})
);
/*
4. **로그인 처리**:
- `/login` 경로에서 POST 요청이 들어오면 `passport.authenticate("local", ...)`을 통해 로그인 처리를 합니다.
- 인증 성공 시 `/secrets`로 리디렉션하고, 실패 시 `/login`으로 리디렉션합니다.
*/
app.post("/register", async (req, res) => {
const email = req.body.username;
const password = req.body.password;
try {
const checkResult = await db.query("SELECT * FROM users WHERE email = $1", [
email,
]);
if (checkResult.rows.length > 0) {
req.redirect("/login");
} else {
bcrypt.hash(password, saltRounds, async (err, hash) => {
if (err) {
console.error("Error hashing password:", err);
} else {
const result = await db.query(
"INSERT INTO users (email, password) VALUES ($1, $2) RETURNING *",
[email, hash]
);
const user = result.rows[0];
req.login(user, (err) => {
console.log("success");
res.redirect("/secrets");
});
}
});
}
} catch (err) {
console.log(err);
}
});
/*
5. **사용자 등록 처리**:
- `/register` 경로에서 POST 요청이 들어오면 사용자의 이메일과 비밀번호를 받습니다.
- 이메일이 이미 데이터베이스에 있는지 확인하고, 없다면 bcrypt를 사용하여 비밀번호를 해시하고 데이터베이스에 저장합니다.
- 사용자를 로그인 상태로 변경하고 `/secrets`로 리디렉션합니다.
*/
passport.use(
new Strategy(async function verify(username, password, cb) {
try {
const result = await db.query("SELECT * FROM users WHERE email = $1 ", [
username,
]);
if (result.rows.length > 0) {
const user = result.rows[0];
const storedHashedPassword = user.password;
bcrypt.compare(password, storedHashedPassword, (err, valid) => {
if (err) {
//Error with password check
console.error("Error comparing passwords:", err);
return cb(err);
} else {
if (valid) {
//Passed password check
return cb(null, user);
} else {
//Did not pass password check
return cb(null, false);
}
}
});
} else {
return cb("User not found");
}
} catch (err) {
console.log(err);
}
})
);
/*
2. **Local Strategy**:
- 로컬 전략을 사용하여 사용자 이름과 비밀번호를 기반으로 인증합니다.
- `passport.use(new Strategy(...))`를 통해 로컬 전략을 정의합니다.
- 사용자가 로그인할 때, 입력한 비밀번호를 데이터베이스에 저장된 해시된 비밀번호와 비교합니다.
*/
passport.serializeUser((user, cb) => {
cb(null, user);
});
passport.deserializeUser((user, cb) => {
cb(null, user);
});
/*
3. **serializeUser와 deserializeUser**:
- `passport.serializeUser`와 `passport.deserializeUser`를 사용하여 사용자 정보를 세션에 저장하고 불러옵니다.
- 사용자 정보를 직렬화하여 세션에 저장하고, 역직렬화하여 세션에서 사용자 정보를 가져옵니다.
*/
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});