Flare-k

[Authenticate] Github Login

......@@ -117,4 +117,6 @@ dist
package-lock.json
uploads
static
\ No newline at end of file
static
text
*.txt
\ No newline at end of file
......
import dotenv from "dotenv";
import express from "express";
import morgan from "morgan";
import helmet from "helmet";
......@@ -12,9 +13,9 @@ import routes from "./routes";
import userRouter from "./routers/userRouter";
import videoRouter from "./routers/videoRouter";
import globalRouter from "./routers/globalRouter";
import "./passport";
dotenv.config();
const app = express();
const CokieStore = MongoStore(session);
......@@ -36,6 +37,7 @@ app.use(
store: new CokieStore({ mongooseConnection: mongoose.connection }),
})
);
app.use(passport.initialize());
app.use(passport.session());
......
......@@ -15,7 +15,7 @@ export const postJoin = async (req, res, next) => {
res.render("join", { pageTitle: "Join" });
} else {
try {
const user = await User.create({
const user = await User({
name,
email,
});
......@@ -33,16 +33,57 @@ export const postJoin = async (req, res, next) => {
export const getLogin = (req, res) =>
res.render("login", { pageTitle: "Login" });
export const postLogin = passport.authenticate("local", {
failureRedirect: routes.login,
successRedirect: routes.home,
});
// 깃허브 로그인
export const githubLogin = passport.authenticate("github");
// call back 받아오는 함수
export const githubLoginCallback = async (
accessToken,
refreshToken,
profile,
cb
) => {
// callback 정보 확인용 console.log
// console.log(accessToken, refreshToken, profile, cb);
const {
_json: { id, avatar_url: avatarUrl, name, email },
} = profile;
// profile 파라미터로 가져온 내용들
// 파라미터로 받은 cb함수가 처리해준다. True->정보를 쿠키에.. False->error
try {
const user = await User.findOne({ email });
if (user) {
user.githubId = id;
user.save();
return cb(null, user);
}
const newUser = await User.create({
email,
name,
githubId: id,
avatarUrl,
});
return cb(null, newUser);
} catch (error) {
return cb(error, null);
}
};
export const postGithubLogin = (req, res) => {
res.redirect(routes.home);
};
// 로그아웃을 클릭하면 LogOut페이지로 가는 것 대신에, 로그아웃을 처리한 후
// home 페이지로 Redirect로 표현할 것이다.
// 즉, 초반에 만들어둔 logout.pug는 삭제해도 좋다.
export const logout = (req, res) => {
// res.render("logout", { pageTitle: "Logout" });
req.logout();
res.redirect(routes.home);
};
......
dotenv.config();
import dotenv from "dotenv";
import app from "./app"; // app.js에서 export default app했기 때문에 불러올 수 있다.
import "./db";
......@@ -5,8 +6,6 @@ import "./models/Video";
import "./models/Comment";
import "./models/User";
dotenv.config();
const PORT = process.env.PORT || 80;
const handleListening = () => {
......
......@@ -35,6 +35,7 @@
"multer": "^1.4.2",
"node-sass": "^4.14.1",
"passport": "^0.4.1",
"passport-github": "^1.1.0",
"passport-local": "^1.0.0",
"passport-local-mongoose": "^6.0.1",
"postcss-loader": "^3.0.0",
......
import dotenv from "dotenv";
import passport from "passport";
import GithubStrategy from "passport-github";
import User from "./models/User";
import { githubLoginCallback } from "./controllers/userController";
import routes from "./routes";
dotenv.config();
// passport에게 strategy(로그인 방식)를 사용하도록 요청한다.
// passportLocalMongooser가 제공하는 strategy를 이용한다. -> username과 password를 사용.
passport.use(User.createStrategy());
passport.use(
new GithubStrategy(
{
clientID: process.env.GH_ID,
clientSecret: process.env.GH_SECRET,
callbackURL: `http://localhost:80${routes.githubCallback}`,
},
githubLoginCallback
)
);
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
......
import express from "express";
import passport from "passport";
import routes from "../routes";
import { home, search } from "../controllers/videoController";
import {
logout,
getJoin,
postJoin,
getLogin,
logout,
postJoin,
postLogin,
githubLogin,
postGithubLogin,
} from "../controllers/userController";
import { onlyPublic } from "../middlewares";
import { onlyPublic, onlyPrivate } from "../middlewares";
const globalRouter = express.Router();
......@@ -20,5 +23,15 @@ globalRouter.post(routes.login, onlyPublic, postLogin);
globalRouter.get(routes.home, home);
globalRouter.get(routes.search, search);
globalRouter.get(routes.logout, logout);
globalRouter.get(routes.logout, onlyPrivate, logout);
globalRouter.get(routes.gitHub, githubLogin);
// callback으로 받아온 정보를 다뤄야하는 함수도 필요하다.
// callback으로 가면 passport.authenticate 처리 해줘야함
globalRouter.get(
routes.githubCallback,
passport.authenticate("github", { failureRedirect: "/login" }),
postGithubLogin
);
export default globalRouter;
......
......@@ -18,6 +18,10 @@ const VIDEO_DETAIL = "/:id";
const EDIT_VIDEO = "/:id/edit";
const DELETE_VIDEO = "/:id/delete";
// Github
const GITHUB = "/auth/github";
const GITHUB_CALLBACK = "/auth/github/callback";
const routes = {
home: HOME,
join: JOIN,
......@@ -57,6 +61,8 @@ const routes = {
return DELETE_VIDEO;
}
},
gitHub: GITHUB,
githubCallback: GITHUB_CALLBACK,
};
// template에서 직접 접근이 필요한 경우 함수로 바꿔준다.
export default routes;
......
......@@ -2,4 +2,26 @@ express session을 설치한다. npm install express-session
postJoin은 이메일과 비밀번호를 전달하고 next()가 호출되어 postLogin으로 간다.
connect mongo를 통해 저장소를 생성한다.
\ No newline at end of file
connect mongo를 통해 저장소를 생성한다.
- 인증에 대한 정리 -
유저네임과 비밀번호를 이용한 방식(local 방식)은 비교적 간단하다. 유저네임과 비밀번호를 post 방식으로 전달하고
설치해준 플러그인인 Mongoose가 자동으로 체크를 해준다. 만약 비밀번호가 맞으면 passport에게 맞다고 알려주고
passport는 쿠키를 생성한다.
소셜로그인의 경우에는 조금 다르다
먼저 사용자는 깃허브 사이트로 이동하게 되고 거기에서 권한 승인을 한다.
그 이후에 깃헙 사이트는 우리에게 해당 사용자의 정보를 보내주는데 /auth/github/callback이라는 URL로 오게 된다
그렇게 되면 passport가 함수를 호출하는데 githubLoginCallback이라는 우리가 만들어준 함수이다.
passport가 이함수를 실행하는 것이다.
이 함수는 모든 사용자 프로필 정보를 받고 이 정보로 필요한 것을 할 수 있다.
githubLoginCallback 함수의 한가지 조건은 callback(cb) 함수를 리턴해야하는 것이다.
cb 함수를 실행시켜서 에러가 있는지 유저가 있는지 알려줘야 한다.
에러가 존재하면 passport는 에러가 있구나 유저는 없구나하고 끝내고
유저가 존재하면 passport는 이 유저를 가져와 쿠키를 만들고 저장한다.
이렇게 저장된 쿠키를 브라우저로 보내게 된다.
globalRouter에서 깃허브로 갈때 githubLogin이 실행되는데 깃허브로 보내주는 역할을 한다.
그리고 githubCallback(URL)로 돌아왔을 때 passport는 사용자가 알려준 함수인 githubLoginCallback을 실행시킨다.
만약 user를 찾으면 passport는 통과시키며 postGithubLogin을 실행하고 홈으로 리다이렉트한다.
......
.social-login
button.social-login--github
span
i.fab.fa-github
| Continue with Github
a(href=routes.gitHub)
span
i.fab.fa-github
| Continue with Github
button.social-login--facebook
span
i.fab.fa-facebook
......