깃헙 프로필의 email이 데이터베이스에 있을때 유저가 로그인할 수 있게 해주었다.
그 말이 즉슨 Github
가 주는 user
의 email
을 쓰겠다는거다.
primary
이면서 verified
된 email
을 찾는다는 거다.
만일 찾았을 경우에 그 email
을 데이터베이스에서 찾는거다.
만일 그 유저를 찾았다면 들어오게 할거다. 로그인 시킨다는 말이다.
그러면 누가 로그인되느냐 먼저 Github
로 계정을 만든 사람이거나
username
과 password
로 계정을 만든 사람이 있는데 두 가지 경우 모두 로그인이
가능하다. 왜냐하면 같은 email
이기 때문이다.
그래서 username
과 password
로 계정을 만든 사람의 경우 Github
을 통해서 로그인도 가능하다.
왜냐하면 데이터베이스에 있는 email
과 Github
에 있는 email
이 같다.
이런식으로 카카오톡으로 계정 생성하는것도 구현할수 있다.
만일 카카오톡이 email
을 return
하면 그 email
을 찾고 해당되는 유저를 찾아
로그인 시켜주는거다.
Github
으로 계정을 만들었든 password
로 만들었든지 간에 말이다.
이게 여기서 적용되는 규칮이다. user
를 찾을 뿐이다.
어떤식으로 로그인 했는지는 관심없다. 어떤 식으로 계정을 만들었는지도 관심없고
Github
가 준것과 똑같은 email
을 찾게 되면 해당 user
를 로그인 시킬거다.
DB
에 Github email
을 가진 user
가 없다면 새로운 계정을 만들어서
그 user
를 로그인 시킬거다.
하지만 schema
의 한 부분을 바꾼 적이 있다. 바로 socialOnly
이다.
socialOnly
는 해당 계정을 password
로 로그인 할수 없다는 것을 알려준다.
이건 오직 소셜 로그인으로만 로그인 할수 있다는 말이다.
그래서 무얼 해볼수가 있냐면 postLogin
으로 와서 username
을 가진 유저를 찾을때
socialOnly
가 false
인 유저만 찾게 만들수 있다.
export const postLogin = async (req, res) => {
const { username, password } = req.body;
const pageTitle = "Login";
const user = await User.findOne({ username, socialOnly: false });
여기 postLogin
에서 form
에 입력한 username
을 가지고
socialOnly
가 false
인 user
를 찾는 거다.
왜냐하면 몇몇 사람들은 Github
로 로그인 했는지 password
를 통해 로그인했는지 잊어 버리기 때문이다.
그래서 여기서 뭘 하고 있냐면 Github
데이터를 가지고 user
를 생성하고 있고
const user = await User.create({
name: userData.name ? userData.name : userData.login,
username: userData.login,
email: emailObj.email,
password: "",
socialOnly: true,
location: userData.location,
});
그 user
를 로그인시키고 있다. 근데 2번씩이나 반복하고 있다.
let existingUser
로 수정해준다.
let existingUser = await User.findOne({ email: emailObj.email });
if (existingUser) {
req.session.loggedIn = true;
req.session.user = existingUser;
return res.redirect("/");
그리고 만일 exstingUser
가 없다면 이부분을 다 실행 할거다.
let user = await User.findOne({ email: emailObj.email });
if (!user) {
user = await User.create({
name: userData.name ? userData.name : userData.login,
username: userData.login,
email: emailObj.email,
password: "",
socialOnly: true,
location: userData.location,
});
}
req.session.loggedIn = true;
req.session.user = user;
return res.redirect("/");
} else {
return res.redirect("/login");
}
};
그리고 마지막엔 이렇게 할거다. 그리고 existingUser
대신 user
라고 한다.
이렇게 user
를 찾고 있고 이 유저를 찾게 되면 이 모든 것들을 건너뛰고 user
를 로그인 할거다.
만일 user
를 못 찾았다면 user
를 새로 만든 user
로 정의 할거다.
그리고 user
를 로그인 할거다.
이미 저번 파트에서 Github
을 통해서 계정을 만들었다.
그래서 어떻게 작동하냐면 이 부분에서 로그인 될거다.
req.session.loggedIn = true;
req.session.user = user;
return res.redirect("/");
테스트해보겠다. 쿠키를 삭제해주고 새로고침을 하면 로그아웃이 되고
Continue with Github
을 눌러서 로그인이 된다.
그리고 데이터베이스에는 한 user
만 있다. 이건 socialOnly
가 true
인 경우에만 일어난다.
이말은 해당 계정은 Github
로 만들어졌고 password
가 없다는 소리이다.
모든 user
를 지우고 쿠키도 지워 본다. 다시 로그아웃 되었다.
그리고 새로운 이메일로 가입을 해 보겠다.
user
를 확인해 보면 socialOnly
는 false
로 나온다.
그 다음에 Github
을 이용해서 로그인해서 작동해 본다. 그리고 다시 user
를 찾아 보면
socialOnly
가 true
로 나온다.
그리고 이제 웹사이트에 계정이 존재한다면 username
과 password
로 로그인했든
Github
로 계정 생성을 했든 로그인 할거다.
Github
에서 가져오는 데이터는 굉장히 중요한 것이다.
그러니
avatar_url
을 저장해 볼수도 있다.
왜냐하면 다음 섹션에서 avatar
와 파일들에 대해 다뤄 볼거다.
avatar_url: 'https://avatars.githubusercontent.com/u/91738673?v=4',
바로 이 url
을 이용해서 말이다.
그래서 이걸 users schema
에 추가해 볼거다.
User.js
에서
const userSchema = new mongoose.Schema({
avatar_url: String,
type
은 string
으로 해준다. 그리고 required
가 아니니깐 그냥 string
만 적어준다.
이건 굉장히 유용하다. 왜냐하면 user
들이 avatar
를 가지고 있길 원한다.
그리고 Github
은 필요한 링크를 준다. avatar_url
을 클릭해보면 프로필 사진을 띄워 준다.
만일
user
가Github
으로부터 넘어왔다면 한가지를 더 추가해 본다.
avatar_url
을 추가한다.
userController.js
에서
user = await User.create({
avatarUrl: userData.avatar_url,
그리고
user
객체들은 전부userData
에서 온다는걸 기억하자.
그러니 userData.avatar_url
을 쓰면 된다.
avatarUrl
이 없는 user
는 email
과 password
로만 계정을 만들었다는 소리이다.
하지만 프로필 수정을 하면 바뀌게 된다.
다시 한번 기억해 본다. userData
는 API
로 부터 오며 emailData
또한 Github API
로부터 온다.
여기 만든 두개의 request
가 있다.
const userData = await (
await fetch(`${apiUrl}/user`, {
headers: {
Authorization: `token ${access_token}`,
},
})
).json();
const emailData = await (
await fetch(`${apiUrl}/user/emails`, {
headers: {
Authorization: `token ${access_token}`,
},
})
).json();
서로 다른 데이터에 접근 할수 있는 같은 토큰을 사용하고 있다.
이제 로그아웃 페이지를 만들어 본다.
로그아웃의 경우 보다시피 url
에 logout
이라 되어 있다.
이게 Router
상에 있는지 확인해 본다. 이미 가지고 있다.
Cannot GET /logout
으로 나오는 이유는 userRouter
에 있어선 안된다.
/users/logout
으로 있어햐 한다.
이말은 template
를 후정해야 한다는 소리이다.
base.pug
로 가서 /users/logout
으로 바꿔준다.
if loggedIn
li
a(href="/users/logout") Log Out
logout
은 무얼 하고 있냐면 logout
은 아무것도 안하고 있다.
그저 Log out
을 보낸 뿐이다.
export const logout = (req, res) => res.send("Log out");
새로고침해서 확인하면 이제 로그아웃 페이지로 넘어가지만 어떤 작업도 하진 않는다.
export const logout = (req, res) => {
req.session.destroy();
return res.redirect("/");
};
이렇게 하면 세션을 없애준다. 그러면 이제 로그아웃을 페이지를 누르면 로그아웃 된다.
그리고 이제 /remove
는 필요없어 졌으니 없애준다.
이제 Github
인증과 로그아웃이 구현되었다.